Table of contents generation, etc

This commit is contained in:
Alex Yatskov 2015-08-09 13:12:17 +09:00
parent bc3067d9f2
commit 7b620031e8
2 changed files with 85 additions and 25 deletions

View File

@ -40,12 +40,22 @@ type list struct {
index int index int
} }
type header struct {
text []byte
level int
children []*header
}
type vimDoc struct { type vimDoc struct {
rootHead *header
lastHead *header
title string
tocPos int
lists []*list lists []*list
} }
func VimDocRenderer() *vimDoc { func VimDocRenderer() blackfriday.Renderer {
return &vimDoc{} return &vimDoc{title: "test", tocPos: -1}
} }
func (v *vimDoc) pushl() { func (v *vimDoc) pushl() {
@ -68,22 +78,41 @@ func (v *vimDoc) getl() *list {
return v.lists[len(v.lists)-1] return v.lists[len(v.lists)-1]
} }
func (v *vimDoc) fixup(input []byte) []byte { func (v *vimDoc) fixupCode(input []byte) []byte {
r := regexp.MustCompile(`(?m)^\s*([<>])$`) r := regexp.MustCompile(`(?m)^\s*([<>])$`)
return r.ReplaceAll(input, []byte("$1")) return r.ReplaceAll(input, []byte("$1"))
} }
func (*vimDoc) hrule(out *bytes.Buffer, repeat string) { func (v *vimDoc) fixupHeader(header []byte) []byte {
return bytes.ToUpper(header)
}
func (v *vimDoc) buildTag(header []byte) []byte {
return []byte(fmt.Sprintf("%s-%s", v.title, string(bytes.ToLower(header))))
}
func (*vimDoc) writeRule(out *bytes.Buffer, repeat string) {
out.WriteString(strings.Repeat(repeat, DEFAULT_NUM_COLUMNS)) out.WriteString(strings.Repeat(repeat, DEFAULT_NUM_COLUMNS))
out.WriteString("\n") out.WriteString("\n")
} }
func (v *vimDoc) writeToc(out *bytes.Buffer, h *header, depth int) {
out.WriteString(fmt.Sprintf(
"%s%s: |%s|\n",
strings.Repeat(" ", depth*blackfriday.TAB_SIZE_DEFAULT),
string(h.text),
v.buildTag(h.text)))
for _, c := range h.children {
v.writeToc(out, c, depth+1)
}
}
func (v *vimDoc) format(out *bytes.Buffer, text string, trim int) { func (v *vimDoc) format(out *bytes.Buffer, text string, trim int) {
lines := strings.Split(text, "\n") lines := strings.Split(text, "\n")
for index, line := range lines { for index, line := range lines {
width := blackfriday.TAB_SIZE_DEFAULT width := blackfriday.TAB_SIZE_DEFAULT
if index == 0 { if width >= trim && index == 0 {
width -= trim width -= trim
} }
@ -117,25 +146,55 @@ func (v *vimDoc) BlockHtml(out *bytes.Buffer, text []byte) {
} }
func (v *vimDoc) Header(out *bytes.Buffer, text func() bool, level int, id string) { func (v *vimDoc) Header(out *bytes.Buffer, text func() bool, level int, id string) {
marker := out.Len() initPos := out.Len()
switch level { switch level {
case 1: case 1:
v.hrule(out, "=") v.writeRule(out, "=")
case 2: case 2:
v.hrule(out, "-") v.writeRule(out, "-")
} }
headerPos := out.Len()
if !text() { if !text() {
out.Truncate(marker) out.Truncate(initPos)
return return
} }
out.WriteString(" ~\n\n") if v.tocPos == -1 && v.rootHead != nil {
v.tocPos = initPos
}
var value []byte
value = append(value, out.Bytes()[headerPos:]...)
header := &header{value, level, nil}
if v.lastHead == nil {
if header.level != 1 {
log.Println("warning: top-level header in document is not a level 1 header")
}
v.rootHead = header
v.lastHead = header
} else {
if v.rootHead.level >= header.level {
log.Println("warning: found header of higher or equal level to the root header")
}
if header.level <= v.lastHead.level {
v.lastHead = header
} else {
v.lastHead.children = append(v.lastHead.children, header)
}
}
out.Truncate(headerPos)
out.WriteString(fmt.Sprintf("%s\t\t*%s*\n\n", v.fixupHeader(header.text), v.buildTag(header.text)))
} }
func (v *vimDoc) HRule(out *bytes.Buffer) { func (v *vimDoc) HRule(out *bytes.Buffer) {
v.hrule(out, "-") v.writeRule(out, "-")
} }
func (v *vimDoc) List(out *bytes.Buffer, text func() bool, flags int) { func (v *vimDoc) List(out *bytes.Buffer, text func() bool, flags int) {
@ -214,6 +273,7 @@ func (*vimDoc) AutoLink(out *bytes.Buffer, link []byte, kind int) {
func (*vimDoc) CodeSpan(out *bytes.Buffer, text []byte) { func (*vimDoc) CodeSpan(out *bytes.Buffer, text []byte) {
r := regexp.MustCompile(`\s`) r := regexp.MustCompile(`\s`)
// vim does not properly highlight spaces in code spans
if !r.Match(text) { if !r.Match(text) {
out.WriteString("`") out.WriteString("`")
out.Write(text) out.Write(text)
@ -230,8 +290,7 @@ func (*vimDoc) Emphasis(out *bytes.Buffer, text []byte) {
} }
func (*vimDoc) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { func (*vimDoc) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
// unimplemented // cannot view images in vim
log.Println("Image is a stub")
} }
func (*vimDoc) LineBreak(out *bytes.Buffer) { func (*vimDoc) LineBreak(out *bytes.Buffer) {
@ -276,9 +335,16 @@ func (*vimDoc) DocumentHeader(out *bytes.Buffer) {
log.Println("DocumentHeader is a stub") log.Println("DocumentHeader is a stub")
} }
func (*vimDoc) DocumentFooter(out *bytes.Buffer) { func (v *vimDoc) DocumentFooter(out *bytes.Buffer) {
// unimplemented var temp bytes.Buffer
log.Println("DocumentFooter is a stub")
temp.Write(out.Bytes()[:v.tocPos])
v.writeToc(&temp, v.rootHead, 0)
temp.WriteString("\n")
temp.Write(out.Bytes()[v.tocPos:])
out.Reset()
out.Write(v.fixupCode(temp.Bytes()))
} }
func (*vimDoc) GetFlags() int { func (*vimDoc) GetFlags() int {

View File

@ -62,14 +62,8 @@ func main() {
} }
renderer := VimDocRenderer() renderer := VimDocRenderer()
extensions := blackfriday.EXTENSION_FENCED_CODE | blackfriday.EXTENSION_NO_INTRA_EMPHASIS | blackfriday.EXTENSION_SPACE_HEADERS
extensions := 0
extensions |= blackfriday.EXTENSION_FENCED_CODE
extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
extensions |= blackfriday.EXTENSION_SPACE_HEADERS
output := blackfriday.Markdown(input, renderer, extensions) output := blackfriday.Markdown(input, renderer, extensions)
output = renderer.fixup(output)
var file *os.File var file *os.File
switch len(args) { switch len(args) {