This commit is contained in:
parent
71838ee0af
commit
58c81bfac5
116
link/parser.go
Normal file
116
link/parser.go
Normal file
|
@ -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(`<a href="%s">`, root.children[1].text(input))))
|
||||
w.Write([]byte(text))
|
||||
w.Write([]byte(`</a>`))
|
||||
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()
|
||||
}
|
Loading…
Reference in New Issue
Block a user