Skip to content

Commit

Permalink
feature/bug(renderer): Support chroma, fix source paragraph (#720)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gdamore authored Jul 12, 2020
1 parent 8b13202 commit 533e63d
Show file tree
Hide file tree
Showing 12 changed files with 85 additions and 42 deletions.
8 changes: 6 additions & 2 deletions LIMITATIONS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`")
Expand Down
10 changes: 7 additions & 3 deletions pkg/renderer/sgml/delimited_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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))
Expand Down
16 changes: 16 additions & 0 deletions pkg/renderer/sgml/html5/delimited_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,22 @@ end</code></pre>
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 := `<div class="listingblock">
<div class="title">Source block title</div>
<div class="content">
<pre class="highlight"><code class="language-brainfart" data-lang="brainfart">int main(int argc, char **argv);</code></pre>
</div>
</div>
`
Expect(RenderHTML(source)).To(MatchHTML(expected))
})

It("with id, title, source and languages attributes", func() {
source := `[#id-for-source-block]
[source,ruby]
Expand Down
9 changes: 0 additions & 9 deletions pkg/renderer/sgml/html5/paragraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,6 @@ const (

delimitedBlockParagraphTmpl = "<p>{{ .CheckStyle }}{{ .Content }}</p>\n"

sourceParagraphTmpl = "<div class=\"listingblock\">\n" +
"<div class=\"content\">\n" +
"<pre class=\"highlight\">" +
`<code{{ if .Language }} class="language-{{ .Language }}" data-lang="{{ .Language }}"{{ end }}>` +
"{{ .Content }}" +
"</code></pre>\n" +
"</div>\n" +
"</div>\n"

verseParagraphTmpl = "<div {{ if .ID }}id=\"{{ .ID }}\" {{ end }}class=\"verseblock\">\n" +
"{{ if .Title }}<div class=\"title\">{{ .Title }}</div>\n{{ end }}" +
"<pre class=\"content\">{{ .Content }}</pre>\n" +
Expand Down
17 changes: 17 additions & 0 deletions pkg/renderer/sgml/html5/paragraph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 := `<div class="listingblock">
<div class="content">
<pre class="chroma highlight"><code data-lang="c"><span class="tok-kt">int</span> <span class="tok-nf">main</span><span class="tok-p">(</span><span class="tok-kt">int</span> <span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-kt">char</span> <span class="tok-o">**</span><span class="tok-n">argv</span><span class="tok-p">);</span></code></pre>
</div>
</div>
`
Expect(RenderHTML(source)).To(MatchHTML(expected))
})
})
})
1 change: 0 additions & 1 deletion pkg/renderer/sgml/html5/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ var templates = sgml.Templates{
SectionHeader: sectionHeaderTmpl,
SidebarBlock: sidebarBlockTmpl,
SourceBlock: sourceBlockTmpl,
SourceParagraph: sourceParagraphTmpl,
StringElement: stringTmpl,
SubscriptText: subscriptTextTmpl,
SuperscriptText: superscriptTextTmpl,
Expand Down
27 changes: 4 additions & 23 deletions pkg/renderer/sgml/paragraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 0 additions & 2 deletions pkg/renderer/sgml/sgml_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ type sgmlRenderer struct {
sectionHeader *textTemplate
sidebarBlock *textTemplate
sourceBlock *textTemplate
sourceParagraph *textTemplate
stringElement *textTemplate
subscriptText *textTemplate
superscriptText *textTemplate
Expand Down Expand Up @@ -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)
Expand Down
1 change: 0 additions & 1 deletion pkg/renderer/sgml/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ type Templates struct {
SectionHeader string
SidebarBlock string
SourceBlock string
SourceParagraph string
StringElement string
SubscriptText string
SuperscriptText string
Expand Down
16 changes: 16 additions & 0 deletions pkg/renderer/sgml/xhtml5/delimited_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,22 @@ end</code></pre>
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 := `<div class="listingblock">
<div class="title">Source block title</div>
<div class="content">
<pre class="highlight"><code class="language-brainfart" data-lang="brainfart">int main(int argc, char **argv);</code></pre>
</div>
</div>
`
Expect(RenderXHTML(source)).To(MatchHTML(expected))
})

It("with html content", func() {
source := `[source]
----
Expand Down
18 changes: 18 additions & 0 deletions pkg/renderer/sgml/xhtml5/paragraph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,24 @@ image::foo.png[]`
<img src="foo.png" alt="quote" width="john doe" height="quote title"/>
</div>
</div>
`
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 := `<div class="listingblock">
<div class="content">
<pre class="chroma highlight"><code data-lang="c"><span class="tok-kt">int</span> <span class="tok-nf">main</span><span class="tok-p">(</span><span class="tok-kt">int</span> <span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-kt">char</span> <span class="tok-o">**</span><span class="tok-n">argv</span><span class="tok-p">);</span></code></pre>
</div>
</div>
`
Expect(RenderXHTML(source)).To(MatchHTML(expected))
})
Expand Down

0 comments on commit 533e63d

Please sign in to comment.