diff options
author | zeripath <art27@cantab.net> | 2020-09-05 16:45:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-05 11:45:10 -0400 |
commit | 9fdb4f887b65a6ddacefc8c7e4580e333d7e4b95 (patch) | |
tree | aa666649a9cac194bb189bcdc1ab7bc1e7ea6bfb /vendor/github.com/niklasfasching | |
parent | e80eda7d01ca0ea06e48f6f2fc22b174c5a5c91a (diff) | |
download | gitea-9fdb4f887b65a6ddacefc8c7e4580e333d7e4b95.tar.gz gitea-9fdb4f887b65a6ddacefc8c7e4580e333d7e4b95.zip |
Update to go-org 1.3.2 (#12728)
* Update to go-org 1.3.2
Fix #12727
Signed-off-by: Andrew Thornton <art27@cantab.net>
* Fix unit test
Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Diffstat (limited to 'vendor/github.com/niklasfasching')
9 files changed, 361 insertions, 101 deletions
diff --git a/vendor/github.com/niklasfasching/go-org/org/block.go b/vendor/github.com/niklasfasching/go-org/org/block.go index 78ad9a7915..11b135fdfa 100644 --- a/vendor/github.com/niklasfasching/go-org/org/block.go +++ b/vendor/github.com/niklasfasching/go-org/org/block.go @@ -10,6 +10,11 @@ type Block struct { Name string Parameters []string Children []Node + Result Node +} + +type Result struct { + Node Node } type Example struct { @@ -19,6 +24,8 @@ type Example struct { var exampleLineRegexp = regexp.MustCompile(`^(\s*):(\s(.*)|\s*$)`) var beginBlockRegexp = regexp.MustCompile(`(?i)^(\s*)#\+BEGIN_(\w+)(.*)`) var endBlockRegexp = regexp.MustCompile(`(?i)^(\s*)#\+END_(\w+)`) +var resultRegexp = regexp.MustCompile(`(?i)^(\s*)#\+RESULTS:`) +var exampleBlockEscapeRegexp = regexp.MustCompile(`(^|\n)([ \t]*),([ \t]*)(\*|,\*|#\+|,#\+)`) func lexBlock(line string) (token, bool) { if m := beginBlockRegexp.FindStringSubmatch(line); m != nil { @@ -29,6 +36,13 @@ func lexBlock(line string) (token, bool) { return nilToken, false } +func lexResult(line string) (token, bool) { + if m := resultRegexp.FindStringSubmatch(line); m != nil { + return token{"result", len(m[1]), "", m}, true + } + return nilToken, false +} + func lexExample(line string) (token, bool) { if m := exampleLineRegexp.FindStringSubmatch(line); m != nil { return token{"example", len(m[1]), m[3], m}, true @@ -45,22 +59,41 @@ func (d *Document) parseBlock(i int, parentStop stopFn) (int, Node) { stop := func(d *Document, i int) bool { return i >= len(d.tokens) || (d.tokens[i].kind == "endBlock" && d.tokens[i].content == name) } - block, i := Block{name, parameters, nil}, i+1 + block, i := Block{name, parameters, nil, nil}, i+1 if isRawTextBlock(name) { rawText := "" for ; !stop(d, i); i++ { rawText += trim(d.tokens[i].matches[0]) + "\n" } + if name == "EXAMPLE" || (name == "SRC" && len(parameters) >= 1 && parameters[0] == "org") { + rawText = exampleBlockEscapeRegexp.ReplaceAllString(rawText, "$1$2$3$4") + } block.Children = d.parseRawInline(rawText) } else { consumed, nodes := d.parseMany(i, stop) block.Children = nodes i += consumed } - if i < len(d.tokens) && d.tokens[i].kind == "endBlock" && d.tokens[i].content == name { - return i + 1 - start, block + if i >= len(d.tokens) || d.tokens[i].kind != "endBlock" || d.tokens[i].content != name { + return 0, nil + } + if name == "SRC" { + consumed, result := d.parseSrcBlockResult(i+1, parentStop) + block.Result = result + i += consumed + } + return i + 1 - start, block +} + +func (d *Document) parseSrcBlockResult(i int, parentStop stopFn) (int, Node) { + start := i + for ; !parentStop(d, i) && d.tokens[i].kind == "text" && d.tokens[i].content == ""; i++ { + } + if parentStop(d, i) || d.tokens[i].kind != "result" { + return 0, nil } - return 0, nil + consumed, result := d.parseResult(i, parentStop) + return (i - start) + consumed, result } func (d *Document) parseExample(i int, parentStop stopFn) (int, Node) { @@ -71,6 +104,14 @@ func (d *Document) parseExample(i int, parentStop stopFn) (int, Node) { return i - start, example } +func (d *Document) parseResult(i int, parentStop stopFn) (int, Node) { + if i+1 >= len(d.tokens) { + return 0, nil + } + consumed, node := d.parseOne(i+1, parentStop) + return consumed + 1, Result{node} +} + func trimIndentUpTo(max int) func(string) string { return func(line string) string { i := 0 @@ -80,5 +121,17 @@ func trimIndentUpTo(max int) func(string) string { } } +func (b Block) ParameterMap() map[string]string { + if len(b.Parameters) == 0 { + return nil + } + m := map[string]string{":lang": b.Parameters[0]} + for i := 1; i+1 < len(b.Parameters); i += 2 { + m[b.Parameters[i]] = b.Parameters[i+1] + } + return m +} + func (n Example) String() string { return orgWriter.WriteNodesAsString(n) } func (n Block) String() string { return orgWriter.WriteNodesAsString(n) } +func (n Result) String() string { return orgWriter.WriteNodesAsString(n) } diff --git a/vendor/github.com/niklasfasching/go-org/org/document.go b/vendor/github.com/niklasfasching/go-org/org/document.go index 3c60e5b54f..0f016c1157 100644 --- a/vendor/github.com/niklasfasching/go-org/org/document.go +++ b/vendor/github.com/niklasfasching/go-org/org/document.go @@ -36,6 +36,8 @@ type Document struct { Path string // Path of the file containing the parse input - used to resolve relative paths during parsing (e.g. INCLUDE). tokens []token baseLvl int + Macros map[string]string + Links map[string]string Nodes []Node NamedNodes map[string]Node Outline Outline // Outline is a Table Of Contents for the document and contains all sections (headline + content). @@ -63,6 +65,7 @@ var lexFns = []lexFn{ lexHeadline, lexDrawer, lexBlock, + lexResult, lexList, lexTable, lexHorizontalRule, @@ -83,7 +86,7 @@ func New() *Configuration { DefaultSettings: map[string]string{ "TODO": "TODO | DONE", "EXCLUDE_TAGS": "noexport", - "OPTIONS": "toc:t <:t e:t f:t pri:t todo:t tags:t", + "OPTIONS": "toc:t <:t e:t f:t pri:t todo:t tags:t title:t", }, Log: log.New(os.Stderr, "go-org: ", 0), ReadFile: ioutil.ReadFile, @@ -120,6 +123,8 @@ func (c *Configuration) Parse(input io.Reader, path string) (d *Document) { Outline: Outline{outlineSection, outlineSection, 0}, BufferSettings: map[string]string{}, NamedNodes: map[string]Node{}, + Links: map[string]string{}, + Macros: map[string]string{}, Path: path, } defer func() { @@ -169,12 +174,13 @@ func (d *Document) Get(key string) string { // - < (export timestamps) // - e (export org entities) // - f (export footnotes) -// - toc (export table of content) +// - title (export title) +// - toc (export table of content. an int limits the included org headline lvl) // - todo (export headline todo status) // - pri (export headline priority) // - tags (export headline tags) // see https://orgmode.org/manual/Export-settings.html for more information -func (d *Document) GetOption(key string) bool { +func (d *Document) GetOption(key string) string { get := func(settings map[string]string) string { for _, field := range strings.Fields(settings["OPTIONS"]) { if strings.HasPrefix(field, key+":") { @@ -187,15 +193,11 @@ func (d *Document) GetOption(key string) bool { if value == "" { value = get(d.DefaultSettings) } - switch value { - case "t": - return true - case "nil": - return false - default: - d.Log.Printf("Bad value for export option %s (%s)", key, value) - return false + if value == "" { + value = "nil" + d.Log.Printf("Missing value for export option %s", key) } + return value } func (d *Document) parseOne(i int, stop stopFn) (consumed int, node Node) { @@ -206,6 +208,8 @@ func (d *Document) parseOne(i int, stop stopFn) (consumed int, node Node) { consumed, node = d.parseTable(i, stop) case "beginBlock": consumed, node = d.parseBlock(i, stop) + case "result": + consumed, node = d.parseResult(i, stop) case "beginDrawer": consumed, node = d.parseDrawer(i, stop) case "text": diff --git a/vendor/github.com/niklasfasching/go-org/org/headline.go b/vendor/github.com/niklasfasching/go-org/org/headline.go index 749d1ff005..7e0b8eb2a6 100644 --- a/vendor/github.com/niklasfasching/go-org/org/headline.go +++ b/vendor/github.com/niklasfasching/go-org/org/headline.go @@ -35,14 +35,14 @@ var tagRegexp = regexp.MustCompile(`(.*?)\s+(:[A-Za-z0-9_@#%:]+:\s*$)`) func lexHeadline(line string) (token, bool) { if m := headlineRegexp.FindStringSubmatch(line); m != nil { - return token{"headline", len(m[1]), m[2], m}, true + return token{"headline", 0, m[2], m}, true } return nilToken, false } func (d *Document) parseHeadline(i int, parentStop stopFn) (int, Node) { t, headline := d.tokens[i], Headline{} - headline.Lvl = t.lvl + headline.Lvl = len(t.matches[1]) headline.Index = d.addHeadline(&headline) @@ -69,7 +69,7 @@ func (d *Document) parseHeadline(i int, parentStop stopFn) (int, Node) { headline.Title = d.parseInline(text) stop := func(d *Document, i int) bool { - return parentStop(d, i) || d.tokens[i].kind == "headline" && d.tokens[i].lvl <= headline.Lvl + return parentStop(d, i) || d.tokens[i].kind == "headline" && len(d.tokens[i].matches[1]) <= headline.Lvl } consumed, nodes := d.parseMany(i+1, stop) if len(nodes) > 0 { diff --git a/vendor/github.com/niklasfasching/go-org/org/html_writer.go b/vendor/github.com/niklasfasching/go-org/org/html_writer.go index d630db5ceb..d66e6effb3 100644 --- a/vendor/github.com/niklasfasching/go-org/org/html_writer.go +++ b/vendor/github.com/niklasfasching/go-org/org/html_writer.go @@ -5,6 +5,7 @@ import ( "html" "log" "regexp" + "strconv" "strings" "unicode" @@ -15,7 +16,7 @@ import ( // HTMLWriter exports an org document into a html document. type HTMLWriter struct { ExtendingWriter Writer - HighlightCodeBlock func(source, lang string) string + HighlightCodeBlock func(source, lang string, inline bool) string strings.Builder document *Document @@ -60,7 +61,10 @@ func NewHTMLWriter() *HTMLWriter { document: &Document{Configuration: defaultConfig}, log: defaultConfig.Log, htmlEscape: true, - HighlightCodeBlock: func(source, lang string) string { + HighlightCodeBlock: func(source, lang string, inline bool) string { + if inline { + return fmt.Sprintf("<div class=\"highlight-inline\">\n<pre>\n%s\n</pre>\n</div>", html.EscapeString(source)) + } return fmt.Sprintf("<div class=\"highlight\">\n<pre>\n%s\n</pre>\n</div>", html.EscapeString(source)) }, footnotes: &footnotes{ @@ -88,7 +92,11 @@ func (w *HTMLWriter) WriterWithExtensions() Writer { func (w *HTMLWriter) Before(d *Document) { w.document = d w.log = d.Log - if title := d.Get("TITLE"); title != "" { + if title := d.Get("TITLE"); title != "" && w.document.GetOption("title") != "nil" { + titleDocument := d.Parse(strings.NewReader(title), d.Path) + if titleDocument.Error == nil { + title = w.WriteNodesAsString(titleDocument.Nodes...) + } w.WriteString(fmt.Sprintf(`<h1 class="title">%s</h1>`+"\n", title)) } w.WriteOutline(d) @@ -102,38 +110,54 @@ func (w *HTMLWriter) WriteComment(Comment) {} func (w *HTMLWriter) WritePropertyDrawer(PropertyDrawer) {} func (w *HTMLWriter) WriteBlock(b Block) { - content := "" - if isRawTextBlock(b.Name) { - builder, htmlEscape := w.Builder, w.htmlEscape - w.Builder, w.htmlEscape = strings.Builder{}, false - WriteNodes(w, b.Children...) - out := w.String() - w.Builder, w.htmlEscape = builder, htmlEscape - content = strings.TrimRightFunc(out, unicode.IsSpace) - } else { - content = w.WriteNodesAsString(b.Children...) - } - switch name := b.Name; { - case name == "SRC": + content, params := w.blockContent(b.Name, b.Children), b.ParameterMap() + + switch b.Name { + case "SRC": + if params[":exports"] == "results" || params[":exports"] == "none" { + break + } lang := "text" if len(b.Parameters) >= 1 { lang = strings.ToLower(b.Parameters[0]) } - content = w.HighlightCodeBlock(content, lang) + content = w.HighlightCodeBlock(content, lang, false) w.WriteString(fmt.Sprintf("<div class=\"src src-%s\">\n%s\n</div>\n", lang, content)) - case name == "EXAMPLE": - w.WriteString(`<pre class="example">` + "\n" + content + "\n</pre>\n") - case name == "EXPORT" && len(b.Parameters) >= 1 && strings.ToLower(b.Parameters[0]) == "html": - w.WriteString(content + "\n") - case name == "QUOTE": + case "EXAMPLE": + w.WriteString(`<pre class="example">` + "\n" + html.EscapeString(content) + "\n</pre>\n") + case "EXPORT": + if len(b.Parameters) >= 1 && strings.ToLower(b.Parameters[0]) == "html" { + w.WriteString(content + "\n") + } + case "QUOTE": w.WriteString("<blockquote>\n" + content + "</blockquote>\n") - case name == "CENTER": + case "CENTER": w.WriteString(`<div class="center-block" style="text-align: center; margin-left: auto; margin-right: auto;">` + "\n") w.WriteString(content + "</div>\n") default: w.WriteString(fmt.Sprintf(`<div class="%s-block">`, strings.ToLower(b.Name)) + "\n") w.WriteString(content + "</div>\n") } + + if b.Result != nil && params[":exports"] != "code" && params[":exports"] != "none" { + WriteNodes(w, b.Result) + } +} + +func (w *HTMLWriter) WriteResult(r Result) { WriteNodes(w, r.Node) } + +func (w *HTMLWriter) WriteInlineBlock(b InlineBlock) { + content := w.blockContent(strings.ToUpper(b.Name), b.Children) + switch b.Name { + case "src": + lang := strings.ToLower(b.Parameters[0]) + content = w.HighlightCodeBlock(content, lang, true) + w.WriteString(fmt.Sprintf("<div class=\"src src-inline src-%s\">\n%s\n</div>", lang, content)) + case "export": + if strings.ToLower(b.Parameters[0]) == "html" { + w.WriteString(content) + } + } } func (w *HTMLWriter) WriteDrawer(d Drawer) { @@ -155,7 +179,7 @@ func (w *HTMLWriter) WriteFootnoteDefinition(f FootnoteDefinition) { } func (w *HTMLWriter) WriteFootnotes(d *Document) { - if !w.document.GetOption("f") || len(w.footnotes.list) == 0 { + if w.document.GetOption("f") == "nil" || len(w.footnotes.list) == 0 { return } w.WriteString(`<div class="footnotes">` + "\n") @@ -183,25 +207,33 @@ func (w *HTMLWriter) WriteFootnotes(d *Document) { } func (w *HTMLWriter) WriteOutline(d *Document) { - if w.document.GetOption("toc") && len(d.Outline.Children) != 0 { + if w.document.GetOption("toc") != "nil" && len(d.Outline.Children) != 0 { + maxLvl, _ := strconv.Atoi(w.document.GetOption("toc")) w.WriteString("<nav>\n<ul>\n") for _, section := range d.Outline.Children { - w.writeSection(section) + w.writeSection(section, maxLvl) } w.WriteString("</ul>\n</nav>\n") } } -func (w *HTMLWriter) writeSection(section *Section) { +func (w *HTMLWriter) writeSection(section *Section, maxLvl int) { + if maxLvl != 0 && section.Headline.Lvl > maxLvl { + return + } // NOTE: To satisfy hugo ExtractTOC() check we cannot use `<li>\n` here. Doesn't really matter, just a note. w.WriteString("<li>") h := section.Headline title := cleanHeadlineTitleForHTMLAnchorRegexp.ReplaceAllString(w.WriteNodesAsString(h.Title...), "") w.WriteString(fmt.Sprintf("<a href=\"#%s\">%s</a>\n", h.ID(), title)) - if len(section.Children) != 0 { + hasChildren := false + for _, section := range section.Children { + hasChildren = hasChildren || maxLvl == 0 || section.Headline.Lvl <= maxLvl + } + if hasChildren { w.WriteString("<ul>\n") for _, section := range section.Children { - w.writeSection(section) + w.writeSection(section, maxLvl) } w.WriteString("</ul>\n") } @@ -217,16 +249,17 @@ func (w *HTMLWriter) WriteHeadline(h Headline) { } } + w.WriteString(fmt.Sprintf(`<div id="outline-container-%s" class="outline-%d">`, h.ID(), h.Lvl+1) + "\n") w.WriteString(fmt.Sprintf(`<h%d id="%s">`, h.Lvl+1, h.ID()) + "\n") - if w.document.GetOption("todo") && h.Status != "" { + if w.document.GetOption("todo") != "nil" && h.Status != "" { w.WriteString(fmt.Sprintf(`<span class="todo">%s</span>`, h.Status) + "\n") } - if w.document.GetOption("pri") && h.Priority != "" { + if w.document.GetOption("pri") != "nil" && h.Priority != "" { w.WriteString(fmt.Sprintf(`<span class="priority">[%s]</span>`, h.Priority) + "\n") } WriteNodes(w, h.Title...) - if w.document.GetOption("tags") && len(h.Tags) != 0 { + if w.document.GetOption("tags") != "nil" && len(h.Tags) != 0 { tags := make([]string, len(h.Tags)) for i, tag := range h.Tags { tags[i] = fmt.Sprintf(`<span>%s</span>`, tag) @@ -235,13 +268,16 @@ func (w *HTMLWriter) WriteHeadline(h Headline) { w.WriteString(fmt.Sprintf(`<span class="tags">%s</span>`, strings.Join(tags, " "))) } w.WriteString(fmt.Sprintf("\n</h%d>\n", h.Lvl+1)) - WriteNodes(w, h.Children...) + if content := w.WriteNodesAsString(h.Children...); content != "" { + w.WriteString(fmt.Sprintf(`<div id="outline-text-%s" class="outline-text-%d">`, h.ID(), h.Lvl+1) + "\n" + content + "</div>\n") + } + w.WriteString("</div>\n") } func (w *HTMLWriter) WriteText(t Text) { if !w.htmlEscape { w.WriteString(t.Content) - } else if !w.document.GetOption("e") || t.IsRaw { + } else if w.document.GetOption("e") == "nil" || t.IsRaw { w.WriteString(html.EscapeString(t.Content)) } else { w.WriteString(html.EscapeString(htmlEntityReplacer.Replace(t.Content))) @@ -277,7 +313,7 @@ func (w *HTMLWriter) WriteExplicitLineBreak(l ExplicitLineBreak) { } func (w *HTMLWriter) WriteFootnoteLink(l FootnoteLink) { - if !w.document.GetOption("f") { + if w.document.GetOption("f") == "nil" { return } i := w.footnotes.add(l) @@ -286,7 +322,7 @@ func (w *HTMLWriter) WriteFootnoteLink(l FootnoteLink) { } func (w *HTMLWriter) WriteTimestamp(t Timestamp) { - if !w.document.GetOption("<") { + if w.document.GetOption("<") == "nil" { return } w.WriteString(`<span class="timestamp"><`) @@ -306,20 +342,46 @@ func (w *HTMLWriter) WriteRegularLink(l RegularLink) { if l.Protocol == "file" { url = url[len("file:"):] } - description := url - if l.Description != nil { - description = w.WriteNodesAsString(l.Description...) + if prefix := w.document.Links[l.Protocol]; prefix != "" { + url = html.EscapeString(prefix) + strings.TrimPrefix(url, l.Protocol+":") } switch l.Kind() { case "image": - w.WriteString(fmt.Sprintf(`<img src="%s" alt="%s" title="%s" />`, url, description, description)) + if l.Description == nil { + w.WriteString(fmt.Sprintf(`<img src="%s" alt="%s" title="%s" />`, url, url, url)) + } else { + description := strings.TrimPrefix(String(l.Description), "file:") + w.WriteString(fmt.Sprintf(`<a href="%s"><img src="%s" alt="%s" /></a>`, url, description, description)) + } case "video": - w.WriteString(fmt.Sprintf(`<video src="%s" title="%s">%s</video>`, url, description, description)) + if l.Description == nil { + w.WriteString(fmt.Sprintf(`<video src="%s" title="%s">%s</video>`, url, url, url)) + } else { + description := strings.TrimPrefix(String(l.Description), "file:") + w.WriteString(fmt.Sprintf(`<a href="%s"><video src="%s" title="%s"></video></a>`, url, description, description)) + } default: + description := url + if l.Description != nil { + description = w.WriteNodesAsString(l.Description...) + } w.WriteString(fmt.Sprintf(`<a href="%s">%s</a>`, url, description)) } } +func (w *HTMLWriter) WriteMacro(m Macro) { + if macro := w.document.Macros[m.Name]; macro != "" { + for i, param := range m.Parameters { + macro = strings.Replace(macro, fmt.Sprintf("$%d", i+1), param, -1) + } + macroDocument := w.document.Parse(strings.NewReader(macro), w.document.Path) + if macroDocument.Error != nil { + w.log.Printf("bad macro: %s -> %s: %v", m.Name, macro, macroDocument.Error) + } + WriteNodes(w, macroDocument.Nodes...) + } +} + func (w *HTMLWriter) WriteList(l List) { tags, ok := listTags[l.Kind] if !ok { @@ -363,11 +425,8 @@ func (w *HTMLWriter) WriteParagraph(p Paragraph) { return } w.WriteString("<p>") - if _, ok := p.Children[0].(LineBreak); !ok { - w.WriteString("\n") - } WriteNodes(w, p.Children...) - w.WriteString("\n</p>\n") + w.WriteString("</p>\n") } func (w *HTMLWriter) WriteExample(e Example) { @@ -414,23 +473,31 @@ func (w *HTMLWriter) WriteNodeWithName(n NodeWithName) { func (w *HTMLWriter) WriteTable(t Table) { w.WriteString("<table>\n") - beforeFirstContentRow := true + inHead := len(t.SeparatorIndices) > 0 && + t.SeparatorIndices[0] != len(t.Rows)-1 && + (t.SeparatorIndices[0] != 0 || len(t.SeparatorIndices) > 1 && t.SeparatorIndices[len(t.SeparatorIndices)-1] != len(t.Rows)-1) + if inHead { + w.WriteString("<thead>\n") + } else { + w.WriteString("<tbody>\n") + } for i, row := range t.Rows { - if row.IsSpecial || len(row.Columns) == 0 { - continue - } - if beforeFirstContentRow { - beforeFirstContentRow = false - if i+1 < len(t.Rows) && len(t.Rows[i+1].Columns) == 0 { - w.WriteString("<thead>\n") - w.writeTableColumns(row.Columns, "th") + if len(row.Columns) == 0 && i != 0 && i != len(t.Rows)-1 { + if inHead { w.WriteString("</thead>\n<tbody>\n") - continue + inHead = false } else { - w.WriteString("<tbody>\n") + w.WriteString("</tbody>\n<tbody>\n") } } - w.writeTableColumns(row.Columns, "td") + if row.IsSpecial { + continue + } + if inHead { + w.writeTableColumns(row.Columns, "th") + } else { + w.writeTableColumns(row.Columns, "td") + } } w.WriteString("</tbody>\n</table>\n") } @@ -472,6 +539,19 @@ func (w *HTMLWriter) withHTMLAttributes(input string, kvs ...string) string { return out.String() } +func (w *HTMLWriter) blockContent(name string, children []Node) string { + if isRawTextBlock(name) { + builder, htmlEscape := w.Builder, w.htmlEscape + w.Builder, w.htmlEscape = strings.Builder{}, false + WriteNodes(w, children...) + out := w.String() + w.Builder, w.htmlEscape = builder, htmlEscape + return strings.TrimRightFunc(out, unicode.IsSpace) + } else { + return w.WriteNodesAsString(children...) + } +} + func setHTMLAttribute(attributes []h.Attribute, k, v string) []h.Attribute { for i, a := range attributes { if strings.ToLower(a.Key) == strings.ToLower(k) { diff --git a/vendor/github.com/niklasfasching/go-org/org/inline.go b/vendor/github.com/niklasfasching/go-org/org/inline.go index c33701d6bf..e7a8f47049 100644 --- a/vendor/github.com/niklasfasching/go-org/org/inline.go +++ b/vendor/github.com/niklasfasching/go-org/org/inline.go @@ -30,6 +30,12 @@ type Emphasis struct { Content []Node } +type InlineBlock struct { + Name string + Parameters []string + Children []Node +} + type LatexFragment struct { OpeningPair string ClosingPair string @@ -48,6 +54,11 @@ type RegularLink struct { AutoLink bool } +type Macro struct { + Name string + Parameters []string +} + var validURLCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=" var autolinkProtocols = regexp.MustCompile(`^(https?|ftp|file)$`) var imageExtensionRegexp = regexp.MustCompile(`^[.](png|gif|jpe?g|svg|tiff?)$`) @@ -58,6 +69,9 @@ var timestampRegexp = regexp.MustCompile(`^<(\d{4}-\d{2}-\d{2})( [A-Za-z]+)?( \d var footnoteRegexp = regexp.MustCompile(`^\[fn:([\w-]*?)(:(.*?))?\]`) var statisticsTokenRegexp = regexp.MustCompile(`^\[(\d+/\d+|\d+%)\]`) var latexFragmentRegexp = regexp.MustCompile(`(?s)^\\begin{(\w+)}(.*)\\end{(\w+)}`) +var inlineBlockRegexp = regexp.MustCompile(`src_(\w+)(\[(.*)\])?{(.*)}`) +var inlineExportBlockRegexp = regexp.MustCompile(`@@(\w+):(.*?)@@`) +var macroRegexp = regexp.MustCompile(`{{{(.*)\((.*)\)}}}`) var timestampFormat = "2006-01-02 Mon 15:04" var datestampFormat = "2006-01-02 Mon" @@ -66,6 +80,7 @@ var latexFragmentPairs = map[string]string{ `\(`: `\)`, `\[`: `\]`, `$$`: `$$`, + `$`: `$`, } func (d *Document) parseInline(input string) (nodes []Node) { @@ -76,25 +91,29 @@ func (d *Document) parseInline(input string) (nodes []Node) { case '^': consumed, node = d.parseSubOrSuperScript(input, current) case '_': - consumed, node = d.parseSubScriptOrEmphasis(input, current) + rewind, consumed, node = d.parseSubScriptOrEmphasisOrInlineBlock(input, current) + case '@': + consumed, node = d.parseInlineExportBlock(input, current) case '*', '/', '+': consumed, node = d.parseEmphasis(input, current, false) case '=', '~': consumed, node = d.parseEmphasis(input, current, true) case '[': consumed, node = d.parseOpeningBracket(input, current) + case '{': + consumed, node = d.parseMacro(input, current) case '<': consumed, node = d.parseTimestamp(input, current) case '\\': consumed, node = d.parseExplicitLineBreakOrLatexFragment(input, current) case '$': - consumed, node = d.parseLatexFragment(input, current) + consumed, node = d.parseLatexFragment(input, current, 1) case '\n': consumed, node = d.parseLineBreak(input, current) case ':': rewind, consumed, node = d.parseAutoLink(input, current) - current -= rewind } + current -= rewind if consumed != 0 { if current > previous { nodes = append(nodes, Text{input[previous:current], false}) @@ -143,6 +162,23 @@ func (d *Document) parseLineBreak(input string, start int) (int, Node) { return i - start, LineBreak{i - start} } +func (d *Document) parseInlineBlock(input string, start int) (int, int, Node) { + if !(strings.HasSuffix(input[:start], "src") && (start-4 < 0 || unicode.IsSpace(rune(input[start-4])))) { + return 0, 0, nil + } + if m := inlineBlockRegexp.FindStringSubmatch(input[start-3:]); m != nil { + return 3, len(m[0]), InlineBlock{"src", strings.Fields(m[1] + " " + m[3]), d.parseRawInline(m[4])} + } + return 0, 0, nil +} + +func (d *Document) parseInlineExportBlock(input string, start int) (int, Node) { + if m := inlineExportBlockRegexp.FindStringSubmatch(input[start:]); m != nil { + return len(m[0]), InlineBlock{"export", m[1:2], d.parseRawInline(m[2])} + } + return 0, nil +} + func (d *Document) parseExplicitLineBreakOrLatexFragment(input string, start int) (int, Node) { switch { case start+2 >= len(input): @@ -153,7 +189,7 @@ func (d *Document) parseExplicitLineBreakOrLatexFragment(input string, start int } } case input[start+1] == '(' || input[start+1] == '[': - return d.parseLatexFragment(input, start) + return d.parseLatexFragment(input, start, 2) case strings.Index(input[start:], `\begin{`) == 0: if m := latexFragmentRegexp.FindStringSubmatch(input[start:]); m != nil { if open, content, close := m[1], m[2], m[3]; open == close { @@ -166,15 +202,18 @@ func (d *Document) parseExplicitLineBreakOrLatexFragment(input string, start int return 0, nil } -func (d *Document) parseLatexFragment(input string, start int) (int, Node) { +func (d *Document) parseLatexFragment(input string, start int, pairLength int) (int, Node) { if start+2 >= len(input) { return 0, nil } - openingPair := input[start : start+2] + if pairLength == 1 && input[start:start+2] == "$$" { + pairLength = 2 + } + openingPair := input[start : start+pairLength] closingPair := latexFragmentPairs[openingPair] - if i := strings.Index(input[start+2:], closingPair); i != -1 { - content := d.parseRawInline(input[start+2 : start+2+i]) - return i + 2 + 2, LatexFragment{openingPair, closingPair, content} + if i := strings.Index(input[start+pairLength:], closingPair); i != -1 { + content := d.parseRawInline(input[start+pairLength : start+pairLength+i]) + return i + pairLength + pairLength, LatexFragment{openingPair, closingPair, content} } return 0, nil } @@ -186,11 +225,14 @@ func (d *Document) parseSubOrSuperScript(input string, start int) (int, Node) { return 0, nil } -func (d *Document) parseSubScriptOrEmphasis(input string, start int) (int, Node) { - if consumed, node := d.parseSubOrSuperScript(input, start); consumed != 0 { - return consumed, node +func (d *Document) parseSubScriptOrEmphasisOrInlineBlock(input string, start int) (int, int, Node) { + if rewind, consumed, node := d.parseInlineBlock(input, start); consumed != 0 { + return rewind, consumed, node + } else if consumed, node := d.parseSubOrSuperScript(input, start); consumed != 0 { + return 0, consumed, node } - return d.parseEmphasis(input, start, false) + consumed, node := d.parseEmphasis(input, start, false) + return 0, consumed, node } func (d *Document) parseOpeningBracket(input string, start int) (int, Node) { @@ -204,6 +246,13 @@ func (d *Document) parseOpeningBracket(input string, start int) (int, Node) { return 0, nil } +func (d *Document) parseMacro(input string, start int) (int, Node) { + if m := macroRegexp.FindStringSubmatch(input[start:]); m != nil { + return len(m[0]), Macro{m[1], strings.Split(m[2], ",")} + } + return 0, nil +} + func (d *Document) parseFootnoteReference(input string, start int) (int, Node) { if m := footnoteRegexp.FindStringSubmatch(input[start:]); m != nil { name, definition := m[1], m[3] @@ -334,6 +383,14 @@ func isValidPostChar(r rune) bool { func isValidBorderChar(r rune) bool { return !unicode.IsSpace(r) } func (l RegularLink) Kind() string { + description := String(l.Description) + descProtocol, descExt := strings.SplitN(description, ":", 2)[0], path.Ext(description) + if ok := descProtocol == "file" || descProtocol == "http" || descProtocol == "https"; ok && imageExtensionRegexp.MatchString(descExt) { + return "image" + } else if ok && videoExtensionRegexp.MatchString(descExt) { + return "video" + } + if p := l.Protocol; l.Description != nil || (p != "" && p != "file" && p != "http" && p != "https") { return "regular" } @@ -351,7 +408,9 @@ func (n LineBreak) String() string { return orgWriter.WriteNodesAsString func (n ExplicitLineBreak) String() string { return orgWriter.WriteNodesAsString(n) } func (n StatisticToken) String() string { return orgWriter.WriteNodesAsString(n) } func (n Emphasis) String() string { return orgWriter.WriteNodesAsString(n) } +func (n InlineBlock) String() string { return orgWriter.WriteNodesAsString(n) } func (n LatexFragment) String() string { return orgWriter.WriteNodesAsString(n) } func (n FootnoteLink) String() string { return orgWriter.WriteNodesAsString(n) } func (n RegularLink) String() string { return orgWriter.WriteNodesAsString(n) } +func (n Macro) String() string { return orgWriter.WriteNodesAsString(n) } func (n Timestamp) String() string { return orgWriter.WriteNodesAsString(n) } diff --git a/vendor/github.com/niklasfasching/go-org/org/keyword.go b/vendor/github.com/niklasfasching/go-org/org/keyword.go index 3ab8804260..c166b95d1b 100644 --- a/vendor/github.com/niklasfasching/go-org/org/keyword.go +++ b/vendor/github.com/niklasfasching/go-org/org/keyword.go @@ -35,7 +35,7 @@ type Include struct { } var keywordRegexp = regexp.MustCompile(`^(\s*)#\+([^:]+):(\s+(.*)|$)`) -var commentRegexp = regexp.MustCompile(`^(\s*)#(.*)`) +var commentRegexp = regexp.MustCompile(`^(\s*)#\s(.*)`) var includeFileRegexp = regexp.MustCompile(`(?i)^"([^"]+)" (src|example|export) (\w+)$`) var attributeRegexp = regexp.MustCompile(`(?:^|\s+)(:[-\w]+)\s+(.*)$`) @@ -62,6 +62,16 @@ func (d *Document) parseKeyword(i int, stop stopFn) (int, Node) { return d.loadSetupFile(k) case "INCLUDE": return d.parseInclude(k) + case "LINK": + if parts := strings.Split(k.Value, " "); len(parts) >= 2 { + d.Links[parts[0]] = parts[1] + } + return 1, k + case "MACRO": + if parts := strings.Split(k.Value, " "); len(parts) >= 2 { + d.Macros[parts[0]] = parts[1] + } + return 1, k case "CAPTION", "ATTR_HTML": consumed, node := d.parseAffiliated(i, stop) if consumed != 0 { @@ -150,7 +160,7 @@ func (d *Document) parseInclude(k Keyword) (int, Node) { d.Log.Printf("Bad include %#v: %s", k, err) return k } - return Block{strings.ToUpper(kind), []string{lang}, d.parseRawInline(string(bs))} + return Block{strings.ToUpper(kind), []string{lang}, d.parseRawInline(string(bs)), nil} } } return 1, Include{k, resolve} diff --git a/vendor/github.com/niklasfasching/go-org/org/org_writer.go b/vendor/github.com/niklasfasching/go-org/org/org_writer.go index d5a33ff27f..c502c7667d 100644 --- a/vendor/github.com/niklasfasching/go-org/org/org_writer.go +++ b/vendor/github.com/niklasfasching/go-org/org/org_writer.go @@ -2,6 +2,7 @@ package org import ( "fmt" + "regexp" "strings" "unicode" "unicode/utf8" @@ -16,6 +17,8 @@ type OrgWriter struct { indent string } +var exampleBlockUnescapeRegexp = regexp.MustCompile(`(^|\n)([ \t]*)(\*|,\*|#\+|,#\+)`) + var emphasisOrgBorders = map[string][]string{ "_": []string{"_", "_"}, "*": []string{"*", "*"}, @@ -90,11 +93,42 @@ func (w *OrgWriter) WriteBlock(b Block) { if isRawTextBlock(b.Name) { w.WriteString(w.indent) } - WriteNodes(w, b.Children...) + content := w.WriteNodesAsString(b.Children...) + if b.Name == "EXAMPLE" || (b.Name == "SRC" && len(b.Parameters) >= 1 && b.Parameters[0] == "org") { + content = exampleBlockUnescapeRegexp.ReplaceAllString(content, "$1$2,$3") + } + w.WriteString(content) if !isRawTextBlock(b.Name) { w.WriteString(w.indent) } w.WriteString("#+END_" + b.Name + "\n") + + if b.Result != nil { + w.WriteString("\n") + WriteNodes(w, b.Result) + } +} + +func (w *OrgWriter) WriteResult(r Result) { + w.WriteString("#+RESULTS:\n") + WriteNodes(w, r.Node) +} + +func (w *OrgWriter) WriteInlineBlock(b InlineBlock) { + switch b.Name { + case "src": + w.WriteString(b.Name + "_" + b.Parameters[0]) + if len(b.Parameters) > 1 { + w.WriteString("[" + strings.Join(b.Parameters[1:], " ") + "]") + } + w.WriteString("{") + WriteNodes(w, b.Children...) + w.WriteString("}") + case "export": + w.WriteString("@@" + b.Parameters[0] + ":") + WriteNodes(w, b.Children...) + w.WriteString("@@") + } } func (w *OrgWriter) WriteDrawer(d Drawer) { @@ -173,7 +207,7 @@ func (w *OrgWriter) WriteNodeWithName(n NodeWithName) { } func (w *OrgWriter) WriteComment(c Comment) { - w.WriteString(w.indent + "#" + c.Content + "\n") + w.WriteString(w.indent + "# " + c.Content + "\n") } func (w *OrgWriter) WriteList(l List) { WriteNodes(w, l.Items...) } @@ -326,3 +360,7 @@ func (w *OrgWriter) WriteRegularLink(l RegularLink) { w.WriteString(fmt.Sprintf("[[%s][%s]]", l.URL, w.WriteNodesAsString(l.Description...))) } } + +func (w *OrgWriter) WriteMacro(m Macro) { + w.WriteString(fmt.Sprintf("{{{%s(%s)}}}", m.Name, strings.Join(m.Parameters, ","))) +} diff --git a/vendor/github.com/niklasfasching/go-org/org/table.go b/vendor/github.com/niklasfasching/go-org/org/table.go index 395588a769..924a64f696 100644 --- a/vendor/github.com/niklasfasching/go-org/org/table.go +++ b/vendor/github.com/niklasfasching/go-org/org/table.go @@ -8,8 +8,9 @@ import ( ) type Table struct { - Rows []Row - ColumnInfos []ColumnInfo + Rows []Row + ColumnInfos []ColumnInfo + SeparatorIndices []int } type Row struct { @@ -23,14 +24,15 @@ type Column struct { } type ColumnInfo struct { - Align string - Len int + Align string + Len int + DisplayLen int } var tableSeparatorRegexp = regexp.MustCompile(`^(\s*)(\|[+-|]*)\s*$`) var tableRowRegexp = regexp.MustCompile(`^(\s*)(\|.*)`) -var columnAlignRegexp = regexp.MustCompile(`^<(l|c|r)>$`) +var columnAlignAndLengthRegexp = regexp.MustCompile(`^<(l|c|r)?(\d+)?>$`) func lexTable(line string) (token, bool) { if m := tableSeparatorRegexp.FindStringSubmatch(line); m != nil { @@ -42,7 +44,7 @@ func lexTable(line string) (token, bool) { } func (d *Document) parseTable(i int, parentStop stopFn) (int, Node) { - rawRows, start := [][]string{}, i + rawRows, separatorIndices, start := [][]string{}, []int{}, i for ; !parentStop(d, i); i++ { if t := d.tokens[i]; t.kind == "tableRow" { rawRow := strings.FieldsFunc(d.tokens[i].content, func(r rune) bool { return r == '|' }) @@ -51,13 +53,14 @@ func (d *Document) parseTable(i int, parentStop stopFn) (int, Node) { } rawRows = append(rawRows, rawRow) } else if t.kind == "tableSeparator" { + separatorIndices = append(separatorIndices, i-start) rawRows = append(rawRows, nil) } else { break } } - table := Table{nil, getColumnInfos(rawRows)} + table := Table{nil, getColumnInfos(rawRows), separatorIndices} for _, rawColumns := range rawRows { row := Row{nil, isSpecialRow(rawColumns)} if len(rawColumns) != 0 { @@ -94,7 +97,7 @@ func getColumnInfos(rows [][]string) []ColumnInfo { columnInfos[i].Len = n } - if m := columnAlignRegexp.FindStringSubmatch(columns[i]); m != nil && isSpecialRow(columns) { + if m := columnAlignAndLengthRegexp.FindStringSubmatch(columns[i]); m != nil && isSpecialRow(columns) { switch m[1] { case "l": columnInfos[i].Align = "left" @@ -103,6 +106,10 @@ func getColumnInfos(rows [][]string) []ColumnInfo { case "r": columnInfos[i].Align = "right" } + if m[2] != "" { + l, _ := strconv.Atoi(m[2]) + columnInfos[i].DisplayLen = l + } } else if _, err := strconv.ParseFloat(columns[i], 32); err == nil { countNumeric++ } else if strings.TrimSpace(columns[i]) != "" { @@ -120,7 +127,7 @@ func getColumnInfos(rows [][]string) []ColumnInfo { func isSpecialRow(rawColumns []string) bool { isAlignRow := true for _, rawColumn := range rawColumns { - if !columnAlignRegexp.MatchString(rawColumn) && rawColumn != "" { + if !columnAlignAndLengthRegexp.MatchString(rawColumn) && rawColumn != "" { isAlignRow = false } } diff --git a/vendor/github.com/niklasfasching/go-org/org/writer.go b/vendor/github.com/niklasfasching/go-org/org/writer.go index 189d72e800..29b64bddb0 100644 --- a/vendor/github.com/niklasfasching/go-org/org/writer.go +++ b/vendor/github.com/niklasfasching/go-org/org/writer.go @@ -18,6 +18,8 @@ type Writer interface { WriteNodeWithName(NodeWithName) WriteHeadline(Headline) WriteBlock(Block) + WriteResult(Result) + WriteInlineBlock(InlineBlock) WriteExample(Example) WriteDrawer(Drawer) WritePropertyDrawer(PropertyDrawer) @@ -34,6 +36,7 @@ type Writer interface { WriteExplicitLineBreak(ExplicitLineBreak) WriteLineBreak(LineBreak) WriteRegularLink(RegularLink) + WriteMacro(Macro) WriteTimestamp(Timestamp) WriteFootnoteLink(FootnoteLink) WriteFootnoteDefinition(FootnoteDefinition) @@ -57,6 +60,10 @@ func WriteNodes(w Writer, nodes ...Node) { w.WriteHeadline(n) case Block: w.WriteBlock(n) + case Result: + w.WriteResult(n) + case InlineBlock: + w.WriteInlineBlock(n) case Example: w.WriteExample(n) case Drawer: @@ -89,6 +96,8 @@ func WriteNodes(w Writer, nodes ...Node) { w.WriteLineBreak(n) case RegularLink: w.WriteRegularLink(n) + case Macro: + w.WriteMacro(n) case Timestamp: w.WriteTimestamp(n) case FootnoteLink: |