package link import ( "bytes" "fmt" "html/template" "io" "strings" ) type Tree struct { cur rng children []Tree } func (t Tree) text(inp string) string { return inp[t.cur.start:t.cur.end] } type rng struct { start, end int typ string } type Parser struct { markers []int ranges []rng stack []Tree } func (p *Parser) pushMarker(start int) { p.markers = append(p.markers, start) p.stack = append(p.stack, Tree{}) } func (p *Parser) popMarker(end int, typ string) { start := p.markers[len(p.markers)-1] p.markers = p.markers[:len(p.markers)-1] cur := rng{start, end, typ} top := p.stack[len(p.stack)-1] top.cur = cur p.stack = p.stack[:len(p.stack)-1] p.stack[len(p.stack)-1].children = append(p.stack[len(p.stack)-1].children, top) p.ranges = append(p.ranges, cur) } func (p *Parser) output() Tree { return p.stack[0].children[0] } func ShowTree(input string, root Tree, indent int) { if root.cur.start != root.cur.end { fmt.Printf("%s + (%s, %d-%d) %q\n", strings.Repeat(" |", indent), root.cur.typ, root.cur.start, root.cur.end, input[root.cur.start:root.cur.end]) } else { indent -= 1 } for _, c := range root.children { ShowTree(input, c, indent+1) } } func formatTitle(w io.Writer, input string, root Tree, indent int) { typ := root.cur.typ text := input[root.cur.start:root.cur.end] if typ == "text" { w.Write([]byte(text)) } if typ == "link" { w.Write([]byte(fmt.Sprintf(``, root.children[1].text(input)))) w.Write([]byte(text)) w.Write([]byte(``)) return } for _, c := range root.children { formatTitle(w, input, c, indent+1) } } func FormatHtmlTitle(input string) template.HTML { p := Parser{} root := p.Parse(input) sb := &bytes.Buffer{} formatTitle(sb, input, root, 0) return template.HTML(sb.String()) } func (p *Parser) Parse(input string) Tree { p.stack = append(p.stack, Tree{}) i := 0 p.pushMarker(i) for i < len(input) { p.pushMarker(i) for i < len(input) && (input[i] != '[' && input[i] != ']') { i++ } p.popMarker(i, "text") if i+2 <= len(input) && input[i:i+2] == "[[" { p.pushMarker(i) p.pushMarker(i) i += 2 p.popMarker(i, "start link tag") p.pushMarker(i) } else if i+2 <= len(input) && input[i:i+2] == "]]" { p.popMarker(i, "link text") p.pushMarker(i) i += 2 p.popMarker(i, "end link tag") p.popMarker(i, "link") } } p.popMarker(i, "full text") return p.output() }