github.com/tada-team/tdproto@v1.51.57/tdmarkup/conv.go (about) 1 package tdmarkup 2 3 import ( 4 "fmt" 5 "html" 6 "log" 7 "strings" 8 "time" 9 10 "github.com/tada-team/tdproto" 11 ) 12 13 type Rules func(middle []rune, e tdproto.MarkupEntity) ([]rune, []rune, []rune) 14 15 const timeFormat = "02.01.06 15:04" 16 17 type ToPlainOpts struct { 18 DisableQuotes bool 19 Location *time.Location 20 } 21 22 func ToHtml(s string, e []tdproto.MarkupEntity) string { 23 return string(conv([]rune(s), e, func(middle []rune, e tdproto.MarkupEntity) ([]rune, []rune, []rune) { 24 switch e.Type { 25 case tdproto.Bold: 26 return []rune("<b>"), middle, []rune("</b>") 27 case tdproto.Italic: 28 return []rune("<i>"), middle, []rune("</i>") 29 case tdproto.Underscore: 30 return []rune("<u>"), middle, []rune("</u>") 31 case tdproto.Code: 32 return []rune("<code>"), middle, []rune("</code>") 33 case tdproto.Strike: 34 return []rune("<s>"), middle, []rune("</s>") 35 case tdproto.CodeBlock: 36 return []rune("<pre>"), middle, []rune("</pre>") 37 case tdproto.Quote: 38 return []rune("<blockquote>"), middle, []rune("</blockquote>\n") 39 case tdproto.Link: 40 return []rune(fmt.Sprintf(`<a href="%s">`, e.Url)), []rune(e.Repl), []rune("</a>") 41 case tdproto.Time: 42 return []rune("<time>"), []rune(mustTime(e.Time).Format(timeFormat)), []rune("</time>") 43 case tdproto.Unsafe: 44 return []rune(""), []rune(html.EscapeString(string(middle))), []rune("") 45 default: 46 return []rune(""), middle, []rune("") 47 } 48 })) 49 } 50 51 func ToPlain(s string, e []tdproto.MarkupEntity, opts *ToPlainOpts) string { 52 if opts == nil { 53 opts = new(ToPlainOpts) 54 } 55 56 row := string(conv([]rune(s), e, func(middle []rune, e tdproto.MarkupEntity) ([]rune, []rune, []rune) { 57 switch e.Type { 58 case tdproto.Quote: 59 if opts.DisableQuotes { 60 return []rune(""), []rune(""), []rune("") 61 } 62 return []rune("> "), middle, []rune("\n") 63 case tdproto.Link: 64 return []rune(""), []rune(e.Repl), []rune("") 65 case tdproto.Time: 66 t := mustTime(e.Time) 67 if loc := opts.Location; loc != nil { 68 t = t.In(loc) 69 } 70 return []rune(""), []rune(t.Format(timeFormat)), []rune("") 71 default: 72 return []rune(""), middle, []rune("") 73 } 74 })) 75 76 if !opts.DisableQuotes { 77 return strings.TrimRight(row, "\n\r") 78 } 79 80 return row 81 } 82 83 func conv(runes []rune, entities []tdproto.MarkupEntity, rules Rules) []rune { 84 if len(entities) == 0 { 85 return runes 86 } 87 88 offset := 0 89 for _, e := range entities { 90 middleDiff := 0 91 middle := runes[e.Open+e.OpenLength+offset : e.Close+offset] 92 op, rulesMiddle, cl := rules(middle, e) 93 94 if len(e.Childs) > 0 { 95 entitiesMiddle := conv(middle, e.Childs, rules) 96 middleDiff = len(entitiesMiddle) - len(middle) 97 middle = entitiesMiddle 98 } else { 99 middleDiff = len(rulesMiddle) - len(middle) 100 middle = rulesMiddle 101 } 102 103 res := make([]rune, 0, len(runes)) 104 res = append(res, runes[:e.Open+offset]...) 105 res = append(res, op...) 106 res = append(res, middle...) 107 res = append(res, cl...) 108 res = append(res, runes[e.Close+e.CloseLength+offset:]...) 109 110 runes = res 111 offset += len(op) + len(cl) - e.OpenLength - e.CloseLength + middleDiff 112 } 113 return runes 114 } 115 116 func mustTime(s string) time.Time { 117 dt, err := time.Parse("2006-01-02T15:04:05Z0700", s) 118 if err != nil { 119 log.Panicln("invalid date:", s, err) 120 } 121 return dt 122 }