From f56b68134a1f05a276268ef78183997fe6cdb29d Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 12 Jul 2020 10:46:14 -0700 Subject: [PATCH] feature/bug(renderer): Support chroma, fix source paragraph This fixes three separate issues (it was natural to fix them all at the same time). Fixes #719 Should not panic on unrecognized source language Fixes #706 Support "Chroma" as a syntax highlighter choice Fixes #704 Source paragraph does not honor syntax highlighter --- LIMITATIONS.adoc | 8 ++++-- README.adoc | 2 +- pkg/renderer/sgml/delimited_block.go | 10 ++++--- .../sgml/html5/delimited_block_test.go | 16 +++++++++++ pkg/renderer/sgml/html5/paragraph.go | 9 ------- pkg/renderer/sgml/html5/paragraph_test.go | 17 ++++++++++++ pkg/renderer/sgml/html5/templates.go | 1 - pkg/renderer/sgml/paragraph.go | 27 +++---------------- pkg/renderer/sgml/sgml_renderer.go | 2 -- pkg/renderer/sgml/templates.go | 1 - .../sgml/xhtml5/delimited_block_test.go | 16 +++++++++++ pkg/renderer/sgml/xhtml5/paragraph_test.go | 18 +++++++++++++ 12 files changed, 85 insertions(+), 42 deletions(-) diff --git a/LIMITATIONS.adoc b/LIMITATIONS.adoc index adb9e170..207a4b1d 100644 --- a/LIMITATIONS.adoc +++ b/LIMITATIONS.adoc @@ -128,9 +128,13 @@ See https://github.com/bytesparadise/libasciidoc/issues/679[Issue #679]. The `favicon` document attribute is not recognized. See https://github.com/bytesparadise/libasciidoc/issues/681[Issue #681]. -== Syntax Highlighters +== Syntax Highlighting -Only the `pygments` highlighter is recognized. +Libasciidoc highlights source code using https://github.com/alecthomas/chroma[Chroma]. +To use it, specify `chroma` for the `source-highlighter` attribute. The value of `pygments` +is treated as an alias. Chroma supports all the standard pygments styles, as well as the vast +majority of the same source code languages. However some more esoteric languages might not be supported. +See https://github.com/alecthomas/chroma#supported-languages[Chroma's documentation] for details. == Math diff --git a/README.adoc b/README.adoc index ae7a9f20..8e55e71e 100644 --- a/README.adoc +++ b/README.adoc @@ -19,7 +19,7 @@ Although it does not support the full Asciidoc/Asciidoctor syntax, Libasciidoc a * Attribute declaration and substitution * Paragraphs and admonition paragraphs * Delimited Blocks (fenced blocks, listing blocks, example blocks, comment blocks, quoted blocks, sidebar blocks, verse blocks) -* Source code highlighting of delimited blocks +* Source code highlighting of delimited blocks (use either `chroma` or `pygments` as the `source-highlighter`) * Literal blocks (paragraph starting with a space, with the `+++....+++` delimiter or with the `[literal]` attribute) * Quoted text (bold, italic, monospace, marked, superscript and subscript) and substitution prevention using the backslash (`\`) character * Single and double quoted typographic quotes (e.g. '`single`' and "`double`") diff --git a/pkg/renderer/sgml/delimited_block.go b/pkg/renderer/sgml/delimited_block.go index 365a71f2..24fbac15 100644 --- a/pkg/renderer/sgml/delimited_block.go +++ b/pkg/renderer/sgml/delimited_block.go @@ -127,13 +127,17 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.Delimite highlighter, _ := ctx.Attributes.GetAsString(types.AttrSyntaxHighlighter) language, found := b.Attributes.GetAsString(types.AttrLanguage) - if found && highlighter == "pygments" { + if found && (highlighter == "chroma" || highlighter == "pygments") { // using github.com/alecthomas/chroma to highlight the content contentBuf := &strings.Builder{} lexer := lexers.Get(language) + if lexer == nil { + lexer = lexers.Fallback + } lexer = chroma.Coalesce(lexer) style := styles.Fallback - if s, found := ctx.Attributes.GetAsString("pygments-style"); found { + + if s, found := ctx.Attributes.GetAsString(highlighter + "-style"); found { style = styles.Get(s) } iterator, err := lexer.Tokenise(nil, content) @@ -145,7 +149,7 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.Delimite html.PreventSurroundingPre(true), } // extra option: inline CSS instead of classes - if ctx.Attributes.GetAsStringWithDefault("pygments-css", "classes") == "style" { + if ctx.Attributes.GetAsStringWithDefault(highlighter+"-css", "classes") == "style" { options = append(options, html.WithClasses(false)) } else { options = append(options, html.WithClasses(true)) diff --git a/pkg/renderer/sgml/html5/delimited_block_test.go b/pkg/renderer/sgml/html5/delimited_block_test.go index 15359010..03b104be 100644 --- a/pkg/renderer/sgml/html5/delimited_block_test.go +++ b/pkg/renderer/sgml/html5/delimited_block_test.go @@ -302,6 +302,22 @@ end Expect(RenderHTML(source)).To(MatchHTML(expected)) }) + It("with title, source and unknown languages attributes", func() { + source := `[source,brainfart] +.Source block title +---- +int main(int argc, char **argv); +----` + expected := `
+
Source block title
+
+
int main(int argc, char **argv);
+
+
+` + Expect(RenderHTML(source)).To(MatchHTML(expected)) + }) + It("with id, title, source and languages attributes", func() { source := `[#id-for-source-block] [source,ruby] diff --git a/pkg/renderer/sgml/html5/paragraph.go b/pkg/renderer/sgml/html5/paragraph.go index ef3dac5d..98bcc105 100644 --- a/pkg/renderer/sgml/html5/paragraph.go +++ b/pkg/renderer/sgml/html5/paragraph.go @@ -20,15 +20,6 @@ const ( delimitedBlockParagraphTmpl = "

{{ .CheckStyle }}{{ .Content }}

\n" - sourceParagraphTmpl = "
\n" + - "
\n" + - "
" +
-		`` +
-		"{{ .Content }}" +
-		"
\n" + - "
\n" + - "
\n" - verseParagraphTmpl = "
\n" + "{{ if .Title }}
{{ .Title }}
\n{{ end }}" + "
{{ .Content }}
\n" + diff --git a/pkg/renderer/sgml/html5/paragraph_test.go b/pkg/renderer/sgml/html5/paragraph_test.go index a96c9e67..fa589a8b 100644 --- a/pkg/renderer/sgml/html5/paragraph_test.go +++ b/pkg/renderer/sgml/html5/paragraph_test.go @@ -477,4 +477,21 @@ image::foo.png[]` }) }) + Context("source paragraphs", func() { + + It("with source and languages attributes", func() { + source := `:source-highlighter: chroma + +[source,c] +int main(int argc, char **argv); +` + expected := `
+
+
int main(int argc, char **argv);
+
+
+` + Expect(RenderHTML(source)).To(MatchHTML(expected)) + }) + }) }) diff --git a/pkg/renderer/sgml/html5/templates.go b/pkg/renderer/sgml/html5/templates.go index e0c2d833..0f5613b7 100644 --- a/pkg/renderer/sgml/html5/templates.go +++ b/pkg/renderer/sgml/html5/templates.go @@ -63,7 +63,6 @@ var templates = sgml.Templates{ SectionHeader: sectionHeaderTmpl, SidebarBlock: sidebarBlockTmpl, SourceBlock: sourceBlockTmpl, - SourceParagraph: sourceParagraphTmpl, StringElement: stringTmpl, SubscriptText: subscriptTextTmpl, SuperscriptText: superscriptTextTmpl, diff --git a/pkg/renderer/sgml/paragraph.go b/pkg/renderer/sgml/paragraph.go index bb5fbc43..1e3647be 100644 --- a/pkg/renderer/sgml/paragraph.go +++ b/pkg/renderer/sgml/paragraph.go @@ -93,30 +93,11 @@ func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p types. } func (r *sgmlRenderer) renderSourceParagraph(ctx *renderer.Context, p types.Paragraph) (string, error) { - log.Debug("rendering source paragraph...") - result := &strings.Builder{} - - content, err := r.renderLines(ctx, p.Lines) - if err != nil { - return "", errors.Wrap(err, "unable to render source paragraph lines") - } - err = r.sourceParagraph.Execute(result, struct { - Context *renderer.Context - ID sanitized - Title sanitized - Language string - Content sanitized - Lines []interface{} - }{ - - Context: ctx, - ID: r.renderElementID(p.Attributes), - Title: r.renderElementTitle(p.Attributes), - Language: p.Attributes.GetAsStringWithDefault(types.AttrLanguage, ""), - Content: sanitized(content), - Lines: p.Lines, + return r.renderSourceBlock(ctx, types.DelimitedBlock{ + Kind: types.Source, + Attributes: p.Attributes, + Elements: p.Lines, }) - return result.String(), err } func (r *sgmlRenderer) renderVerseParagraph(ctx *renderer.Context, p types.Paragraph) (string, error) { diff --git a/pkg/renderer/sgml/sgml_renderer.go b/pkg/renderer/sgml/sgml_renderer.go index 1bbb0ca9..6837df8f 100644 --- a/pkg/renderer/sgml/sgml_renderer.go +++ b/pkg/renderer/sgml/sgml_renderer.go @@ -63,7 +63,6 @@ type sgmlRenderer struct { sectionHeader *textTemplate sidebarBlock *textTemplate sourceBlock *textTemplate - sourceParagraph *textTemplate stringElement *textTemplate subscriptText *textTemplate superscriptText *textTemplate @@ -144,7 +143,6 @@ func (r *sgmlRenderer) prepareTemplates() error { r.stringElement, err = r.newTemplate("string-element", tmpls.StringElement, err) r.sidebarBlock, err = r.newTemplate("sidebar-block", tmpls.SidebarBlock, err) r.sourceBlock, err = r.newTemplate("source-block", tmpls.SourceBlock, err) - r.sourceParagraph, err = r.newTemplate("source-paragraph", tmpls.SourceParagraph, err) r.subscriptText, err = r.newTemplate("subscript", tmpls.SubscriptText, err) r.superscriptText, err = r.newTemplate("superscript", tmpls.SuperscriptText, err) r.table, err = r.newTemplate("table", tmpls.Table, err) diff --git a/pkg/renderer/sgml/templates.go b/pkg/renderer/sgml/templates.go index 0e361277..11037589 100644 --- a/pkg/renderer/sgml/templates.go +++ b/pkg/renderer/sgml/templates.go @@ -56,7 +56,6 @@ type Templates struct { SectionHeader string SidebarBlock string SourceBlock string - SourceParagraph string StringElement string SubscriptText string SuperscriptText string diff --git a/pkg/renderer/sgml/xhtml5/delimited_block_test.go b/pkg/renderer/sgml/xhtml5/delimited_block_test.go index bb2c60ca..3e7383c8 100644 --- a/pkg/renderer/sgml/xhtml5/delimited_block_test.go +++ b/pkg/renderer/sgml/xhtml5/delimited_block_test.go @@ -327,6 +327,22 @@ end Expect(RenderXHTML(source)).To(MatchHTML(expected)) }) + It("with title, source and unknown languages attributes", func() { + source := `[source,brainfart] +.Source block title +---- +int main(int argc, char **argv); +----` + expected := `
+
Source block title
+
+
int main(int argc, char **argv);
+
+
+` + Expect(RenderXHTML(source)).To(MatchHTML(expected)) + }) + It("with html content", func() { source := `[source] ---- diff --git a/pkg/renderer/sgml/xhtml5/paragraph_test.go b/pkg/renderer/sgml/xhtml5/paragraph_test.go index 2ae4e44e..44ab4b03 100644 --- a/pkg/renderer/sgml/xhtml5/paragraph_test.go +++ b/pkg/renderer/sgml/xhtml5/paragraph_test.go @@ -466,6 +466,24 @@ image::foo.png[]` quote
+` + Expect(RenderXHTML(source)).To(MatchHTML(expected)) + }) + }) + + Context("source paragraphs", func() { + + It("with source and languages attributes", func() { + source := `:source-highlighter: chroma + +[source,c] +int main(int argc, char **argv); +` + expected := `
+
+
int main(int argc, char **argv);
+
+
` Expect(RenderXHTML(source)).To(MatchHTML(expected)) })