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  }