diff --git a/link/parser.go b/link/parser.go new file mode 100644 index 0000000..36617e6 --- /dev/null +++ b/link/parser.go @@ -0,0 +1,116 @@ +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() +}