Skip to content

Commit

Permalink
fix: use a class with line links when requested (#692)
Browse files Browse the repository at this point in the history
Fixes #683
  • Loading branch information
alecthomas committed Nov 1, 2022
1 parent 5e27ea4 commit d0e811c
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 117 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -185,7 +185,7 @@ following constructor options:
- `ClassPrefix(prefix)` - prefix each generated CSS class.
- `TabWidth(width)` - Set the rendered tab width, in characters.
- `WithLineNumbers()` - Render line numbers (style with `LineNumbers`).
- `LinkableLineNumbers()` - Make the line numbers linkable and be a link to themselves.
- `WithLinkableLineNumbers()` - Make the line numbers linkable and be a link to themselves.
- `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`).
- `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans.

Expand Down
1 change: 1 addition & 0 deletions bin/.stringer-0.1.11.pkg
1 change: 1 addition & 0 deletions bin/stringer
2 changes: 1 addition & 1 deletion cmd/chroma/main.go
Expand Up @@ -267,7 +267,7 @@ func configureHTMLFormatter(ctx *kong.Context) {
html.WithLineNumbers(cli.HTMLLines),
html.LineNumbersInTable(cli.HTMLLinesTable),
html.PreventSurroundingPre(cli.HTMLPreventSurroundingPre),
html.LinkableLineNumbers(cli.HTMLLinkableLines, "L"),
html.WithLinkableLineNumbers(cli.HTMLLinkableLines, "L"),
}
if len(cli.HTMLHighlight) > 0 {
ranges := [][2]int{}
Expand Down
13 changes: 7 additions & 6 deletions formatters/html/html.go
Expand Up @@ -100,9 +100,9 @@ func LineNumbersInTable(b bool) Option {
}
}

// LinkableLineNumbers decorates the line numbers HTML elements with an "id"
// WithLinkableLineNumbers decorates the line numbers HTML elements with an "id"
// attribute so they can be linked.
func LinkableLineNumbers(b bool, prefix string) Option {
func WithLinkableLineNumbers(b bool, prefix string) Option {
return func(f *Formatter) {
f.linkableLineNumbers = b
f.lineNumbersIDPrefix = prefix
Expand Down Expand Up @@ -262,7 +262,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.
fmt.Fprintf(w, "<span%s>", f.styleAttr(css, chroma.LineHighlight))
}

fmt.Fprintf(w, "<span%s%s>%s\n</span>", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(lineDigits, line))
fmt.Fprintf(w, "<span%s%s>%s\n</span>", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(css, lineDigits, line))

if highlight {
fmt.Fprintf(w, "</span>")
Expand Down Expand Up @@ -302,7 +302,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.

// Line number
if f.lineNumbers && !wrapInTable {
fmt.Fprintf(w, "<span%s%s>%s</span>", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(lineDigits, line))
fmt.Fprintf(w, "<span%s%s>%s</span>", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(css, lineDigits, line))
}

fmt.Fprintf(w, `<span%s>`, f.styleAttr(css, chroma.CodeLine))
Expand Down Expand Up @@ -345,12 +345,12 @@ func (f *Formatter) lineIDAttribute(line int) string {
return fmt.Sprintf(" id=\"%s\"", f.lineID(line))
}

func (f *Formatter) lineTitleWithLinkIfNeeded(lineDigits, line int) string {
func (f *Formatter) lineTitleWithLinkIfNeeded(css map[chroma.TokenType]string, lineDigits, line int) string {
title := fmt.Sprintf("%*d", lineDigits, line)
if !f.linkableLineNumbers {
return title
}
return fmt.Sprintf("<a style=\"outline: none; text-decoration:none; color:inherit\" href=\"#%s\">%s</a>", f.lineID(line), title)
return fmt.Sprintf("<a%s href=\"#%s\">%s</a>", f.styleAttr(css, chroma.LineLink), f.lineID(line), title)
}

func (f *Formatter) lineID(line int) string {
Expand Down Expand Up @@ -520,6 +520,7 @@ func (f *Formatter) styleToCSS(style *chroma.Style) map[chroma.TokenType]string
classes[chroma.LineNumbersTable] = lineNumbersStyle + classes[chroma.LineNumbersTable]
classes[chroma.LineTable] = "border-spacing: 0; padding: 0; margin: 0; border: 0;" + classes[chroma.LineTable]
classes[chroma.LineTableTD] = "vertical-align: top; padding: 0; margin: 0; border: 0;" + classes[chroma.LineTableTD]
classes[chroma.LineLink] = "outline: none; text-decoration:none; color:inherit" + classes[chroma.LineLink]
return classes
}

Expand Down
13 changes: 7 additions & 6 deletions formatters/html/html_test.go
Expand Up @@ -199,29 +199,30 @@ func TestPreWrapper(t *testing.T) {
}

func TestLinkeableLineNumbers(t *testing.T) {
f := New(WithClasses(true), WithLineNumbers(true), LinkableLineNumbers(true, "line"))
f := New(WithClasses(true), WithLineNumbers(true), WithLinkableLineNumbers(true, "line"), WithClasses(false))
it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(\"hello world\")\n}\n")
assert.NoError(t, err)

var buf bytes.Buffer
err = f.Format(&buf, styles.Fallback, it)
assert.NoError(t, err)

assert.Contains(t, buf.String(), `id="line1"><a style="outline: none; text-decoration:none; color:inherit" href="#line1">1</a>`)
assert.Contains(t, buf.String(), `id="line5"><a style="outline: none; text-decoration:none; color:inherit" href="#line5">5</a>`)
assert.Contains(t, buf.String(), `id="line1"><a style="outline:none;text-decoration:none;color:inherit" href="#line1">1</a>`)
assert.Contains(t, buf.String(), `id="line5"><a style="outline:none;text-decoration:none;color:inherit" href="#line5">5</a>`)
}

func TestTableLinkeableLineNumbers(t *testing.T) {
f := New(WithClasses(true), WithLineNumbers(true), LineNumbersInTable(true), LinkableLineNumbers(true, "line"))
f := New(Standalone(true), WithClasses(true), WithLineNumbers(true), LineNumbersInTable(true), WithLinkableLineNumbers(true, "line"))
it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(`hello world`)\n}\n")
assert.NoError(t, err)

var buf bytes.Buffer
err = f.Format(&buf, styles.Fallback, it)
assert.NoError(t, err)

assert.Contains(t, buf.String(), `id="line1"><a style="outline: none; text-decoration:none; color:inherit" href="#line1">1</a>`)
assert.Contains(t, buf.String(), `id="line5"><a style="outline: none; text-decoration:none; color:inherit" href="#line5">5</a>`)
assert.Contains(t, buf.String(), `id="line1"><a class="lnlinks" href="#line1">1</a>`)
assert.Contains(t, buf.String(), `id="line5"><a class="lnlinks" href="#line5">5</a>`)
assert.Contains(t, buf.String(), `/* LineLinks */ .chroma .lnlinks { outline: none; text-decoration:none; color:inherit }`, buf.String())
}

func TestTableLineNumberSpacing(t *testing.T) {
Expand Down
208 changes: 105 additions & 103 deletions tokentype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions types.go
Expand Up @@ -35,6 +35,8 @@ const (
LineTable
// Line numbers table TD wrapper style.
LineTableTD
// Line number links.
LineLink
// Code line wrapper style.
CodeLine
// Input that could not be tokenised.
Expand Down Expand Up @@ -216,6 +218,7 @@ var (
LineHighlight: "hl",
LineTable: "lntable",
LineTableTD: "lntd",
LineLink: "lnlinks",
CodeLine: "cl",
Text: "",
Whitespace: "w",
Expand Down

0 comments on commit d0e811c

Please sign in to comment.