From 9b56fc914c80f6b8a6f6dde9c19d70ff7e79a89b Mon Sep 17 00:00:00 2001 From: Kisaragi Hiu Date: Mon, 18 Jul 2022 03:51:04 +0900 Subject: [PATCH 1/3] highlight: Expose node params so we can pass options to Chroma --- blorg/util.go | 2 +- main.go | 2 +- org/html_writer.go | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/blorg/util.go b/blorg/util.go index 05d74e2..e24ea9a 100644 --- a/blorg/util.go +++ b/blorg/util.go @@ -55,7 +55,7 @@ func getWriter() org.Writer { return w } -func highlightCodeBlock(source, lang string, inline bool) string { +func highlightCodeBlock(source, lang string, inline bool, params map[string]string) string { var w strings.Builder l := lexers.Get(lang) if l == nil { diff --git a/main.go b/main.go index 0b0a21a..c400d56 100644 --- a/main.go +++ b/main.go @@ -119,7 +119,7 @@ func render(args []string) { } } -func highlightCodeBlock(source, lang string, inline bool) string { +func highlightCodeBlock(source, lang string, inline bool, params map[string]string) string { var w strings.Builder l := lexers.Get(lang) if l == nil { diff --git a/org/html_writer.go b/org/html_writer.go index fc0780a..5f388d9 100644 --- a/org/html_writer.go +++ b/org/html_writer.go @@ -19,7 +19,7 @@ import ( // HTMLWriter exports an org document into a html document. type HTMLWriter struct { ExtendingWriter Writer - HighlightCodeBlock func(source, lang string, inline bool) string + HighlightCodeBlock func(source, lang string, inline bool, params map[string]string) string PrettyRelativeLinks bool strings.Builder @@ -66,7 +66,7 @@ func NewHTMLWriter() *HTMLWriter { document: &Document{Configuration: defaultConfig}, log: defaultConfig.Log, htmlEscape: true, - HighlightCodeBlock: func(source, lang string, inline bool) string { + HighlightCodeBlock: func(source, lang string, inline bool, params map[string]string) string { if inline { return fmt.Sprintf("
\n
\n%s\n
\n
", html.EscapeString(source)) } @@ -129,7 +129,7 @@ func (w *HTMLWriter) WriteBlock(b Block) { if len(b.Parameters) >= 1 { lang = strings.ToLower(b.Parameters[0]) } - content = w.HighlightCodeBlock(content, lang, false) + content = w.HighlightCodeBlock(content, lang, false, params) w.WriteString(fmt.Sprintf("
\n%s\n
\n", lang, content)) case "EXAMPLE": w.WriteString(`
` + "\n" + html.EscapeString(content) + "\n
\n") @@ -159,7 +159,7 @@ func (w *HTMLWriter) WriteInlineBlock(b InlineBlock) { switch b.Name { case "src": lang := strings.ToLower(b.Parameters[0]) - content = w.HighlightCodeBlock(content, lang, true) + content = w.HighlightCodeBlock(content, lang, true, nil) w.WriteString(fmt.Sprintf("
\n%s\n
", lang, content)) case "export": if strings.ToLower(b.Parameters[0]) == "html" { From ab8d3bc16ab1c8d97f0f0df60f5627126c6cad03 Mon Sep 17 00:00:00 2001 From: Kisaragi Hiu Date: Mon, 18 Jul 2022 03:56:15 +0900 Subject: [PATCH 2/3] highlight: support highlighting lines in the default writer The hl_lines key is specifically the same as Hugo's key. --- blorg/util.go | 9 +++++- main.go | 9 +++++- org/testdata/hl-lines.html | 12 ++++++++ org/testdata/hl-lines.org | 9 ++++++ org/testdata/hl-lines.pretty_org | 9 ++++++ org/util.go | 51 ++++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 org/testdata/hl-lines.html create mode 100644 org/testdata/hl-lines.org create mode 100644 org/testdata/hl-lines.pretty_org diff --git a/blorg/util.go b/blorg/util.go index e24ea9a..ef588db 100644 --- a/blorg/util.go +++ b/blorg/util.go @@ -63,7 +63,14 @@ func highlightCodeBlock(source, lang string, inline bool, params map[string]stri } l = chroma.Coalesce(l) it, _ := l.Tokenise(nil, source) - _ = html.New().Format(&w, styles.Get("github"), it) + options := []html.Option{} + if params[":hl_lines"] != "" { + ranges := org.ParseRanges(params[":hl_lines"]) + if ranges != nil { + options = append(options, html.HighlightLines(ranges)) + } + } + _ = html.New(options...).Format(&w, styles.Get("github"), it) if inline { return `
` + "\n" + w.String() + "\n" + `
` } diff --git a/main.go b/main.go index c400d56..62a22f3 100644 --- a/main.go +++ b/main.go @@ -127,7 +127,14 @@ func highlightCodeBlock(source, lang string, inline bool, params map[string]stri } l = chroma.Coalesce(l) it, _ := l.Tokenise(nil, source) - _ = html.New().Format(&w, styles.Get("friendly"), it) + options := []html.Option{} + if params[":hl_lines"] != "" { + ranges := org.ParseRanges(params[":hl_lines"]) + if ranges != nil { + options = append(options, html.HighlightLines(ranges)) + } + } + _ = html.New(options...).Format(&w, styles.Get("friendly"), it) if inline { return `
` + "\n" + w.String() + "\n" + `
` } diff --git a/org/testdata/hl-lines.html b/org/testdata/hl-lines.html new file mode 100644 index 0000000..c458903 --- /dev/null +++ b/org/testdata/hl-lines.html @@ -0,0 +1,12 @@ +

Lines in a source block can be highlighted with :hl_lines.

+
+
+
+(+ 1 2)
+(+ 1 2)
+(+ 1 2)
+(+ 1 2)
+(+ 1 2)
+
+
+
diff --git a/org/testdata/hl-lines.org b/org/testdata/hl-lines.org new file mode 100644 index 0000000..17851b8 --- /dev/null +++ b/org/testdata/hl-lines.org @@ -0,0 +1,9 @@ +Lines in a source block can be highlighted with =:hl_lines=. + +#+begin_src emacs-lisp :hl_lines 3-4 +(+ 1 2) +(+ 1 2) +(+ 1 2) +(+ 1 2) +(+ 1 2) +#+end_src diff --git a/org/testdata/hl-lines.pretty_org b/org/testdata/hl-lines.pretty_org new file mode 100644 index 0000000..5d7ba70 --- /dev/null +++ b/org/testdata/hl-lines.pretty_org @@ -0,0 +1,9 @@ +Lines in a source block can be highlighted with =:hl_lines=. + +#+BEGIN_SRC emacs-lisp :hl_lines 3-4 +(+ 1 2) +(+ 1 2) +(+ 1 2) +(+ 1 2) +(+ 1 2) +#+END_SRC diff --git a/org/util.go b/org/util.go index c25bf27..b83b6f4 100644 --- a/org/util.go +++ b/org/util.go @@ -1,5 +1,10 @@ package org +import ( + "strconv" + "strings" +) + func isSecondBlankLine(d *Document, i int) bool { if i-1 <= 0 { return false @@ -17,3 +22,49 @@ func isImageOrVideoLink(n Node) bool { } return false } + +// Parse ranges like this: +// "3-5" -> [[3, 5]] +// "3 8-10" -> [[3, 3], [8, 10]] +// "3 5 6" -> [[3, 3], [5, 5], [6, 6]] +// +// This is Hugo's hlLinesToRanges with "startLine" removed and errors +// ignored. +func ParseRanges(s string) [][2]int { + var ranges [][2]int + s = strings.TrimSpace(s) + if s == "" { + return ranges + } + fields := strings.Split(s, " ") + for _, field := range fields { + field = strings.TrimSpace(field) + if field == "" { + continue + } + numbers := strings.Split(field, "-") + var r [2]int + if len(numbers) > 1 { + first, err := strconv.Atoi(numbers[0]) + if err != nil { + return ranges + } + second, err := strconv.Atoi(numbers[1]) + if err != nil { + return ranges + } + r[0] = first + r[1] = second + } else { + first, err := strconv.Atoi(numbers[0]) + if err != nil { + return ranges + } + r[0] = first + r[1] = first + } + + ranges = append(ranges, r) + } + return ranges +} From a7a960c460d01bd7e68e683be2ede54b6ae4d3a5 Mon Sep 17 00:00:00 2001 From: Kisaragi Hiu Date: Mon, 25 Jul 2022 19:27:11 +0900 Subject: [PATCH 3/3] highlight: add tests for ParseRanges --- org/util_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 org/util_test.go diff --git a/org/util_test.go b/org/util_test.go new file mode 100644 index 0000000..3e1ad89 --- /dev/null +++ b/org/util_test.go @@ -0,0 +1,38 @@ +package org + +import ( + "fmt" + "testing" +) + +var parseRangesTests = map[string][][2]int{ + "3-5": {{3, 5}}, + "3 8-10": {{3, 3}, {8, 10}}, + "3 5 6": {{3, 3}, {5, 5}, {6, 6}}, + " 9-10 5-6 3 ": {{9, 10}, {5, 6}, {3, 3}}, +} + +func TestParseRanges(t *testing.T) { + for s, expected := range parseRangesTests { + t.Run(s, func(t *testing.T) { + actual := ParseRanges(s) + // If this fails it looks like: + // util_test.go:: 9-10 5-6 3 : + // --- Actual + // +++ Expected + // @@ -1 +1 @@ + // -[[9 10] [5 9] [3 3]] + // +[[9 10] [5 6] [3 3]] + if len(actual) != len(expected) { + t.Errorf("%v:\n%v", s, diff(fmt.Sprintf("%v", actual), fmt.Sprintf("%v", expected))) + } else { + for i := range actual { + if actual[i] != expected[i] { + t.Errorf("%v:\n%v", s, diff(fmt.Sprintf("%v", actual), fmt.Sprintf("%v", expected))) + } + } + } + }) + } + +}