Merge pull request #59 from johnsto/master

Header ID specifiers
pull/60/head
Vytautas Šaltenis 2014-04-11 21:31:27 +03:00
commit c5ece173ad
5 changed files with 90 additions and 6 deletions

View File

@ -186,6 +186,24 @@ func (p *parser) prefixHeader(out *bytes.Buffer, data []byte) int {
for end = i; data[end] != '\n'; end++ {
}
skip := end
id := ""
if p.flags&EXTENSION_HEADER_IDS != 0 {
j, k := 0, 0
// find start/end of header id
for j = i; j < end - 1 && (data[j] != '{' || data[j+1] != '#'); j++ {
}
for k = j + 1; k < end && data[k] != '}'; k++ {
}
// extract header id iff found
if j < end && k < end {
id = string(data[j+2:k])
end = j
skip = k + 1
for end > 0 && data[end-1] == ' ' {
end--
}
}
}
for end > 0 && data[end-1] == '#' {
end--
}
@ -197,7 +215,7 @@ func (p *parser) prefixHeader(out *bytes.Buffer, data []byte) int {
p.inline(out, data[i:end])
return true
}
p.r.Header(out, work, level)
p.r.Header(out, work, level, id)
}
return skip
}
@ -1218,7 +1236,7 @@ func (p *parser) paragraph(out *bytes.Buffer, data []byte) int {
return true
}
}(out, p, data[prev:eol])
p.r.Header(out, work, level)
p.r.Header(out, work, level, "")
// find the end of the underline
for data[i] != '\n' {

View File

@ -177,6 +177,66 @@ func TestPrefixHeaderSpaceExtension(t *testing.T) {
doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS)
}
func TestPrefixHeaderIdExtension(t *testing.T) {
var tests = []string{
"# Header 1 {#someid}\n",
"<h1 id=\"someid\">Header 1</h1>\n",
"# Header 1 {#someid} \n",
"<h1 id=\"someid\">Header 1</h1>\n",
"# Header 1 {#someid}\n",
"<h1 id=\"someid\">Header 1</h1>\n",
"# Header 1 {#someid\n",
"<h1>Header 1 {#someid</h1>\n",
"# Header 1 {#someid\n",
"<h1>Header 1 {#someid</h1>\n",
"# Header 1 {#someid}}\n",
"<h1 id=\"someid\">Header 1</h1>\n\n<p>}</p>\n",
"## Header 2 {#someid}\n",
"<h2 id=\"someid\">Header 2</h2>\n",
"### Header 3 {#someid}\n",
"<h3 id=\"someid\">Header 3</h3>\n",
"#### Header 4 {#someid}\n",
"<h4 id=\"someid\">Header 4</h4>\n",
"##### Header 5 {#someid}\n",
"<h5 id=\"someid\">Header 5</h5>\n",
"###### Header 6 {#someid}\n",
"<h6 id=\"someid\">Header 6</h6>\n",
"####### Header 7 {#someid}\n",
"<h6 id=\"someid\"># Header 7</h6>\n",
"# Header 1 # {#someid}\n",
"<h1 id=\"someid\">Header 1</h1>\n",
"## Header 2 ## {#someid}\n",
"<h2 id=\"someid\">Header 2</h2>\n",
"Hello\n# Header 1\nGoodbye\n",
"<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
"* List\n# Header {#someid}\n* List\n",
"<ul>\n<li><p>List</p>\n\n<h1 id=\"someid\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
"* List\n#Header {#someid}\n* List\n",
"<ul>\n<li><p>List</p>\n\n<h1 id=\"someid\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
"* List\n * Nested list\n # Nested header {#someid}\n",
"<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
"<h1 id=\"someid\">Nested header</h1></li>\n</ul></li>\n</ul>\n",
}
doTestsBlock(t, tests, EXTENSION_HEADER_IDS)
}
func TestUnderlineHeaders(t *testing.T) {
var tests = []string{
"Header 1\n========\n",

View File

@ -181,11 +181,13 @@ func (options *Html) GetFlags() int {
return options.flags
}
func (options *Html) Header(out *bytes.Buffer, text func() bool, level int) {
func (options *Html) Header(out *bytes.Buffer, text func() bool, level int, id string) {
marker := out.Len()
doubleSpace(out)
if options.flags&HTML_TOC != 0 {
if id != "" {
out.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id))
} else if options.flags&HTML_TOC != 0 {
// headerCount is incremented in htmlTocHeader
out.WriteString(fmt.Sprintf("<h%d id=\"toc_%d\">", level, options.headerCount))
} else {

View File

@ -68,7 +68,7 @@ func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) {
out.WriteString("\n\\end{verbatim}\n")
}
func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int) {
func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int, id string) {
marker := out.Len()
switch level {

View File

@ -39,6 +39,7 @@ const (
EXTENSION_TAB_SIZE_EIGHT // expand tabs to eight spaces instead of four
EXTENSION_FOOTNOTES // Pandoc-style footnotes
EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, order list, unorder list)block
EXTENSION_HEADER_IDS // specify header IDs with {#id}
)
// These are the possible flag values for the link renderer.
@ -133,7 +134,7 @@ type Renderer interface {
BlockCode(out *bytes.Buffer, text []byte, lang string)
BlockQuote(out *bytes.Buffer, text []byte)
BlockHtml(out *bytes.Buffer, text []byte)
Header(out *bytes.Buffer, text func() bool, level int)
Header(out *bytes.Buffer, text func() bool, level int, id string)
HRule(out *bytes.Buffer)
List(out *bytes.Buffer, text func() bool, flags int)
ListItem(out *bytes.Buffer, text []byte, flags int)
@ -226,6 +227,8 @@ func MarkdownBasic(input []byte) []byte {
// * Strikethrough support
//
// * Strict header parsing
//
// * Custom Header IDs
func MarkdownCommon(input []byte) []byte {
// set up the HTML renderer
htmlFlags := 0
@ -244,6 +247,7 @@ func MarkdownCommon(input []byte) []byte {
extensions |= EXTENSION_AUTOLINK
extensions |= EXTENSION_STRIKETHROUGH
extensions |= EXTENSION_SPACE_HEADERS
extensions |= EXTENSION_HEADER_IDS
return Markdown(input, renderer, extensions)
}