diff options
Diffstat (limited to 'helpers')
-rw-r--r-- | helpers/content.go | 45 | ||||
-rw-r--r-- | helpers/general.go | 27 | ||||
-rw-r--r-- | helpers/general_test.go | 13 | ||||
-rw-r--r-- | helpers/pygments.go | 402 | ||||
-rw-r--r-- | helpers/pygments_test.go | 300 |
5 files changed, 26 insertions, 761 deletions
diff --git a/helpers/content.go b/helpers/content.go index 357bd48e7..941475461 100644 --- a/helpers/content.go +++ b/helpers/content.go @@ -32,7 +32,6 @@ import ( bp "github.com/gohugoio/hugo/bufferpool" "github.com/gohugoio/hugo/config" "github.com/spf13/afero" - jww "github.com/spf13/jwalterweatherman" "strings" ) @@ -58,9 +57,6 @@ type ContentSpec struct { BuildExpired bool BuildDrafts bool - Highlight func(code, lang, optsStr string) (string, error) - defatultPygmentsOpts map[string]string - Cfg config.Provider } @@ -77,36 +73,10 @@ func NewContentSpec(cfg config.Provider, logger *loggers.Logger, contentFs afero Cfg: cfg, } - // Highlighting setup - options, err := parseDefaultPygmentsOpts(cfg) - if err != nil { - return nil, err - } - spec.defatultPygmentsOpts = options - - // Use the Pygmentize on path if present - useClassic := false - h := newHiglighters(spec) - - if cfg.GetBool("pygmentsUseClassic") { - if !hasPygments() { - jww.WARN.Println("Highlighting with pygmentsUseClassic set requires Pygments to be installed and in the path") - } else { - useClassic = true - } - } - - if useClassic { - spec.Highlight = h.pygmentsHighlight - } else { - spec.Highlight = h.chromaHighlight - } - converterProvider, err := markup.NewConverterProvider(converter.ProviderConfig{ Cfg: cfg, ContentFs: contentFs, Logger: logger, - Highlight: spec.Highlight, }) if err != nil { return nil, err @@ -220,6 +190,21 @@ func (c *ContentSpec) RenderMarkdown(src []byte) ([]byte, error) { return b.Bytes(), nil } +func (c *ContentSpec) ResolveMarkup(in string) string { + in = strings.ToLower(in) + switch in { + case "md", "markdown", "mdown": + return "markdown" + case "html", "htm": + return "html" + default: + if conv := c.Converters.Get(in); conv != nil { + return conv.Name() + } + } + return "" +} + // TotalWords counts instance of one or more consecutive white space // characters, as defined by unicode.IsSpace, in s. // This is a cheaper way of word counting than the obvious len(strings.Fields(s)). diff --git a/helpers/general.go b/helpers/general.go index 80c0591b2..259bcf8f4 100644 --- a/helpers/general.go +++ b/helpers/general.go @@ -44,11 +44,6 @@ import ( // FilePathSeparator as defined by os.Separator. const FilePathSeparator = string(filepath.Separator) -// Strips carriage returns from third-party / external processes (useful for Windows) -func normalizeExternalHelperLineFeeds(content []byte) []byte { - return bytes.Replace(content, []byte("\r"), []byte(""), -1) -} - // FindAvailablePort returns an available and valid TCP port. func FindAvailablePort() (*net.TCPAddr, error) { l, err := net.Listen("tcp", ":0") @@ -74,28 +69,6 @@ func InStringArray(arr []string, el string) bool { return false } -// GuessType attempts to guess the type of file from a given string. -func GuessType(in string) string { - switch strings.ToLower(in) { - case "md", "markdown", "mdown": - return "markdown" - case "asciidoc", "adoc", "ad": - return "asciidoc" - case "mmark": - return "mmark" - case "rst": - return "rst" - case "pandoc", "pdc": - return "pandoc" - case "html", "htm": - return "html" - case "org": - return "org" - } - - return "" -} - // FirstUpper returns a string with the first character as upper case. func FirstUpper(s string) string { if s == "" { diff --git a/helpers/general_test.go b/helpers/general_test.go index e5e5e56ed..b8a98fb69 100644 --- a/helpers/general_test.go +++ b/helpers/general_test.go @@ -19,11 +19,20 @@ import ( "strings" "testing" + "github.com/spf13/viper" + + "github.com/gohugoio/hugo/common/loggers" + qt "github.com/frankban/quicktest" "github.com/spf13/afero" ) -func TestGuessType(t *testing.T) { +func TestResolveMarkup(t *testing.T) { + c := qt.New(t) + cfg := viper.New() + spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs()) + c.Assert(err, qt.IsNil) + for i, this := range []struct { in string expect string @@ -43,7 +52,7 @@ func TestGuessType(t *testing.T) { {"org", "org"}, {"excel", ""}, } { - result := GuessType(this.in) + result := spec.ResolveMarkup(this.in) if result != this.expect { t.Errorf("[%d] got %s but expected %s", i, result, this.expect) } diff --git a/helpers/pygments.go b/helpers/pygments.go deleted file mode 100644 index 4d7631ced..000000000 --- a/helpers/pygments.go +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright 2019 The Hugo Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package helpers - -import ( - "bytes" - "crypto/sha1" - "fmt" - "io" - "io/ioutil" - "os/exec" - "path/filepath" - "regexp" - "sort" - "strconv" - "strings" - - "github.com/alecthomas/chroma" - "github.com/alecthomas/chroma/formatters" - "github.com/alecthomas/chroma/formatters/html" - "github.com/alecthomas/chroma/lexers" - "github.com/alecthomas/chroma/styles" - bp "github.com/gohugoio/hugo/bufferpool" - - "github.com/gohugoio/hugo/config" - "github.com/gohugoio/hugo/hugofs" - jww "github.com/spf13/jwalterweatherman" -) - -const pygmentsBin = "pygmentize" - -// hasPygments checks to see if Pygments is installed and available -// on the system. -func hasPygments() bool { - if _, err := exec.LookPath(pygmentsBin); err != nil { - return false - } - return true -} - -type highlighters struct { - cs *ContentSpec - ignoreCache bool - cacheDir string -} - -func newHiglighters(cs *ContentSpec) highlighters { - return highlighters{cs: cs, ignoreCache: cs.Cfg.GetBool("ignoreCache"), cacheDir: cs.Cfg.GetString("cacheDir")} -} - -func (h highlighters) chromaHighlight(code, lang, optsStr string) (string, error) { - opts, err := h.cs.parsePygmentsOpts(optsStr) - if err != nil { - jww.ERROR.Print(err.Error()) - return code, err - } - - style, found := opts["style"] - if !found || style == "" { - style = "friendly" - } - - f, err := h.cs.chromaFormatterFromOptions(opts) - if err != nil { - jww.ERROR.Print(err.Error()) - return code, err - } - - b := bp.GetBuffer() - defer bp.PutBuffer(b) - - err = chromaHighlight(b, code, lang, style, f) - if err != nil { - jww.ERROR.Printf("Highlight failed: %s\nLang: %q\nCode: \n%s", err, lang, code) - return code, err - } - - return h.injectCodeTag(`<div class="highlight">`+b.String()+"</div>", lang), nil -} - -func (h highlighters) pygmentsHighlight(code, lang, optsStr string) (string, error) { - options, err := h.cs.createPygmentsOptionsString(optsStr) - - if err != nil { - jww.ERROR.Print(err.Error()) - return code, nil - } - - // Try to read from cache first - hash := sha1.New() - io.WriteString(hash, code) - io.WriteString(hash, lang) - io.WriteString(hash, options) - - fs := hugofs.Os - - var cachefile string - - if !h.ignoreCache && h.cacheDir != "" { - cachefile = filepath.Join(h.cacheDir, fmt.Sprintf("pygments-%x", hash.Sum(nil))) - - exists, err := Exists(cachefile, fs) - if err != nil { - jww.ERROR.Print(err.Error()) - return code, nil - } - if exists { - f, err := fs.Open(cachefile) - if err != nil { - jww.ERROR.Print(err.Error()) - return code, nil - } - - s, err := ioutil.ReadAll(f) - if err != nil { - jww.ERROR.Print(err.Error()) - return code, nil - } - - return string(s), nil - } - } - - // No cache file, render and cache it - var out bytes.Buffer - var stderr bytes.Buffer - - var langOpt string - if lang == "" { - langOpt = "-g" // Try guessing the language - } else { - langOpt = "-l" + lang - } - - cmd := exec.Command(pygmentsBin, langOpt, "-fhtml", "-O", options) - cmd.Stdin = strings.NewReader(code) - cmd.Stdout = &out - cmd.Stderr = &stderr - - if err := cmd.Run(); err != nil { - jww.ERROR.Print(stderr.String()) - return code, err - } - - str := string(normalizeExternalHelperLineFeeds(out.Bytes())) - - str = h.injectCodeTag(str, lang) - - if !h.ignoreCache && cachefile != "" { - // Write cache file - if err := WriteToDisk(cachefile, strings.NewReader(str), fs); err != nil { - jww.ERROR.Print(stderr.String()) - } - } - - return str, nil -} - -var preRe = regexp.MustCompile(`(?s)(.*?<pre.*?>)(.*?)(</pre>)`) - -func (h highlighters) injectCodeTag(code, lang string) string { - if lang == "" { - return code - } - codeTag := fmt.Sprintf(`<code class="language-%s" data-lang="%s">`, lang, lang) - return preRe.ReplaceAllString(code, fmt.Sprintf("$1%s$2</code>$3", codeTag)) -} - -func chromaHighlight(w io.Writer, source, lexer, style string, f chroma.Formatter) error { - l := lexers.Get(lexer) - if l == nil { - l = lexers.Analyse(source) - } - if l == nil { - l = lexers.Fallback - } - l = chroma.Coalesce(l) - - if f == nil { - f = formatters.Fallback - } - - s := styles.Get(style) - if s == nil { - s = styles.Fallback - } - - it, err := l.Tokenise(nil, source) - if err != nil { - return err - } - - return f.Format(w, s, it) -} - -var pygmentsKeywords = make(map[string]bool) - -func init() { - pygmentsKeywords["encoding"] = true - pygmentsKeywords["outencoding"] = true - pygmentsKeywords["nowrap"] = true - pygmentsKeywords["full"] = true - pygmentsKeywords["title"] = true - pygmentsKeywords["style"] = true - pygmentsKeywords["noclasses"] = true - pygmentsKeywords["classprefix"] = true - pygmentsKeywords["cssclass"] = true - pygmentsKeywords["cssstyles"] = true - pygmentsKeywords["prestyles"] = true - pygmentsKeywords["linenos"] = true - pygmentsKeywords["hl_lines"] = true - pygmentsKeywords["linenostart"] = true - pygmentsKeywords["linenostep"] = true - pygmentsKeywords["linenospecial"] = true - pygmentsKeywords["nobackground"] = true - pygmentsKeywords["lineseparator"] = true - pygmentsKeywords["lineanchors"] = true - pygmentsKeywords["linespans"] = true - pygmentsKeywords["anchorlinenos"] = true - pygmentsKeywords["startinline"] = true -} - -func parseOptions(defaults map[string]string, in string) (map[string]string, error) { - in = strings.Trim(in, " ") - opts := make(map[string]string) - - for k, v := range defaults { - opts[k] = v - } - - if in == "" { - return opts, nil - } - - for _, v := range strings.Split(in, ",") { - keyVal := strings.Split(v, "=") - key := strings.ToLower(strings.Trim(keyVal[0], " ")) - if len(keyVal) != 2 || !pygmentsKeywords[key] { - return opts, fmt.Errorf("invalid Pygments option: %s", key) - } - opts[key] = keyVal[1] - } - - return opts, nil -} - -func createOptionsString(options map[string]string) string { - var keys []string - for k := range options { - keys = append(keys, k) - } - sort.Strings(keys) - - var optionsStr string - for i, k := range keys { - optionsStr += fmt.Sprintf("%s=%s", k, options[k]) - if i < len(options)-1 { - optionsStr += "," - } - } - - return optionsStr -} - -func parseDefaultPygmentsOpts(cfg config.Provider) (map[string]string, error) { - options, err := parseOptions(nil, cfg.GetString("pygmentsOptions")) - if err != nil { - return nil, err - } - - if cfg.IsSet("pygmentsStyle") { - options["style"] = cfg.GetString("pygmentsStyle") - } - - if cfg.IsSet("pygmentsUseClasses") { - if cfg.GetBool("pygmentsUseClasses") { - options["noclasses"] = "false" - } else { - options["noclasses"] = "true" - } - - } - - if _, ok := options["encoding"]; !ok { - options["encoding"] = "utf8" - } - - return options, nil -} - -func (cs *ContentSpec) chromaFormatterFromOptions(pygmentsOpts map[string]string) (chroma.Formatter, error) { - var options = []html.Option{html.TabWidth(4)} - - if pygmentsOpts["noclasses"] == "false" { - options = append(options, html.WithClasses()) - } - - lineNumbers := pygmentsOpts["linenos"] - if lineNumbers != "" { - options = append(options, html.WithLineNumbers()) - if lineNumbers != "inline" { - options = append(options, html.LineNumbersInTable()) - } - } - - startLineStr := pygmentsOpts["linenostart"] - var startLine = 1 - if startLineStr != "" { - - line, err := strconv.Atoi(strings.TrimSpace(startLineStr)) - if err == nil { - startLine = line - options = append(options, html.BaseLineNumber(startLine)) - } - } - - hlLines := pygmentsOpts["hl_lines"] - - if hlLines != "" { - ranges, err := hlLinesToRanges(startLine, hlLines) - - if err == nil { - options = append(options, html.HighlightLines(ranges)) - } - } - - return html.New(options...), nil -} - -func (cs *ContentSpec) parsePygmentsOpts(in string) (map[string]string, error) { - opts, err := parseOptions(cs.defatultPygmentsOpts, in) - if err != nil { - return nil, err - } - return opts, nil - -} - -func (cs *ContentSpec) createPygmentsOptionsString(in string) (string, error) { - opts, err := cs.parsePygmentsOpts(in) - if err != nil { - return "", err - } - return createOptionsString(opts), nil -} - -// startLine compansates for https://github.com/alecthomas/chroma/issues/30 -func hlLinesToRanges(startLine int, s string) ([][2]int, error) { - var ranges [][2]int - s = strings.TrimSpace(s) - - if s == "" { - return ranges, nil - } - - // Variants: - // 1 2 3 4 - // 1-2 3-4 - // 1-2 3 - // 1 3-4 - // 1 3-4 - fields := strings.Split(s, " ") - for _, field := range fields { - field = strings.TrimSpace(field) - if field == "" { - continue - } - numbers := strings.Split(field, "-") - var r [2]int - first, err := strconv.Atoi(numbers[0]) - if err != nil { - return ranges, err - } - first = first + startLine - 1 - r[0] = first - if len(numbers) > 1 { - second, err := strconv.Atoi(numbers[1]) - if err != nil { - return ranges, err - } - second = second + startLine - 1 - r[1] = second - } else { - r[1] = first - } - - ranges = append(ranges, r) - } - return ranges, nil - -} diff --git a/helpers/pygments_test.go b/helpers/pygments_test.go deleted file mode 100644 index 05d86e104..000000000 --- a/helpers/pygments_test.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2015 The Hugo Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package helpers - -import ( - "fmt" - "reflect" - "testing" - - "github.com/alecthomas/chroma/formatters/html" - - qt "github.com/frankban/quicktest" - "github.com/spf13/viper" -) - -func TestParsePygmentsArgs(t *testing.T) { - c := qt.New(t) - - for i, this := range []struct { - in string - pygmentsStyle string - pygmentsUseClasses bool - expect1 interface{} - }{ - {"", "foo", true, "encoding=utf8,noclasses=false,style=foo"}, - {"style=boo,noclasses=true", "foo", true, "encoding=utf8,noclasses=true,style=boo"}, - {"Style=boo, noClasses=true", "foo", true, "encoding=utf8,noclasses=true,style=boo"}, - {"noclasses=true", "foo", true, "encoding=utf8,noclasses=true,style=foo"}, - {"style=boo", "foo", true, "encoding=utf8,noclasses=false,style=boo"}, - {"boo=invalid", "foo", false, false}, - {"style", "foo", false, false}, - } { - - v := viper.New() - v.Set("pygmentsStyle", this.pygmentsStyle) - v.Set("pygmentsUseClasses", this.pygmentsUseClasses) - spec, err := NewContentSpec(v, nil, nil) - c.Assert(err, qt.IsNil) - - result1, err := spec.createPygmentsOptionsString(this.in) - if b, ok := this.expect1.(bool); ok && !b { - if err == nil { - t.Errorf("[%d] parsePygmentArgs didn't return an expected error", i) - } - } else { - if err != nil { - t.Errorf("[%d] parsePygmentArgs failed: %s", i, err) - continue - } - if result1 != this.expect1 { - t.Errorf("[%d] parsePygmentArgs got %v but expected %v", i, result1, this.expect1) - } - - } - } -} - -func TestParseDefaultPygmentsArgs(t *testing.T) { - c := qt.New(t) - - expect := "encoding=utf8,noclasses=false,style=foo" - - for i, this := range []struct { - in string - pygmentsStyle interface{} - pygmentsUseClasses interface{} - pygmentsOptions string - }{ - {"", "foo", true, "style=override,noclasses=override"}, - {"", nil, nil, "style=foo,noclasses=false"}, - {"style=foo,noclasses=false", nil, nil, "style=override,noclasses=override"}, - {"style=foo,noclasses=false", "override", false, "style=override,noclasses=override"}, - } { - v := viper.New() - - v.Set("pygmentsOptions", this.pygmentsOptions) - - if s, ok := this.pygmentsStyle.(string); ok { - v.Set("pygmentsStyle", s) - } - - if b, ok := this.pygmentsUseClasses.(bool); ok { - v.Set("pygmentsUseClasses", b) - } - - spec, err := NewContentSpec(v, nil, nil) - c.Assert(err, qt.IsNil) - - result, err := spec.createPygmentsOptionsString(this.in) - if err != nil { - t.Errorf("[%d] parsePygmentArgs failed: %s", i, err) - continue - } - if result != expect { - t.Errorf("[%d] parsePygmentArgs got %v but expected %v", i, result, expect) - } - } -} - -type chromaInfo struct { - classes bool - lineNumbers bool - lineNumbersInTable bool - highlightRangesLen int - highlightRangesStr string - baseLineNumber int -} - -func formatterChromaInfo(f *html.Formatter) chromaInfo { - v := reflect.ValueOf(f).Elem() - c := chromaInfo{} - // Hack: - - c.classes = f.Classes - c.lineNumbers = v.FieldByName("lineNumbers").Bool() - c.lineNumbersInTable = v.FieldByName("lineNumbersInTable").Bool() - c.baseLineNumber = int(v.FieldByName("baseLineNumber").Int()) - vv := v.FieldByName("highlightRanges") - c.highlightRangesLen = vv.Len() - c.highlightRangesStr = fmt.Sprint(vv) - - return c -} - -func TestChromaHTMLHighlight(t *testing.T) { - c := qt.New(t) - - v := viper.New() - v.Set("pygmentsUseClasses", true) - spec, err := NewContentSpec(v, nil, nil) - c.Assert(err, qt.IsNil) - - result, err := spec.Highlight(`echo "Hello"`, "bash", "") - c.Assert(err, qt.IsNil) - - c.Assert(result, qt.Contains, `<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s2">"Hello"</span></code></pre></div>`) - -} - -func TestChromaHTMLFormatterFromOptions(t *testing.T) { - c := qt.New(t) - - for i, this := range []struct { - in string - pygmentsStyle interface{} - pygmentsUseClasses interface{} - pygmentsOptions string - assert func(c chromaInfo) - }{ - {"", "monokai", true, "style=manni,noclasses=true", func(ci chromaInfo) { - c.Assert(ci.classes, qt.Equals, true) - c.Assert(ci.lineNumbers, qt.Equals, false) - c.Assert(ci.highlightRangesLen, qt.Equals, 0) - - }}, - {"", nil, nil, "style=monokai,noclasses=false", func(ci chromaInfo) { - c.Assert(ci.classes, qt.Equals, true) - }}, - {"linenos=sure,hl_lines=1 2 3", nil, nil, "style=monokai,noclasses=false", func(ci chromaInfo) { - c.Assert(ci.classes, qt.Equals, true) - c.Assert(ci.lineNumbers, qt.Equals, true) - c.Assert(ci.highlightRangesLen, qt.Equals, 3) - c.Assert(ci.highlightRangesStr, qt.Equals, "[[1 1] [2 2] [3 3]]") - c.Assert(ci.baseLineNumber, qt.Equals, 1) - }}, - {"linenos=inline,hl_lines=1,linenostart=4", nil, nil, "style=monokai,noclasses=false", func(ci chromaInfo) { - c.Assert(ci.classes, qt.Equals, true) - c.Assert(ci.lineNumbers, qt.Equals, true) - c.Assert(ci.lineNumbersInTable, qt.Equals, false) - c.Assert(ci.highlightRangesLen, qt.Equals, 1) - // This compansates for https://github.com/alecthomas/chroma/issues/30 - c.Assert(ci.highlightRangesStr, qt.Equals, "[[4 4]]") - c.Assert(ci.baseLineNumber, qt.Equals, 4) - }}, - {"linenos=table", nil, nil, "style=monokai", func(ci chromaInfo) { - c.Assert(ci.lineNumbers, qt.Equals, true) - c.Assert(ci.lineNumbersInTable, qt.Equals, true) - }}, - {"style=monokai,noclasses=false", nil, nil, "style=manni,noclasses=true", func(ci chromaInfo) { - c.Assert(ci.classes, qt.Equals, true) - }}, - {"style=monokai,noclasses=true", "friendly", false, "style=manni,noclasses=false", func(ci chromaInfo) { - c.Assert(ci.classes, qt.Equals, false) - }}, - } { - v := viper.New() - - v.Set("pygmentsOptions", this.pygmentsOptions) - - if s, ok := this.pygmentsStyle.(string); ok { - v.Set("pygmentsStyle", s) - } - - if b, ok := this.pygmentsUseClasses.(bool); ok { - v.Set("pygmentsUseClasses", b) - } - - spec, err := NewContentSpec(v, nil, nil) - c.Assert(err, qt.IsNil) - - opts, err := spec.parsePygmentsOpts(this.in) - if err != nil { - t.Fatalf("[%d] parsePygmentsOpts failed: %s", i, err) - } - - chromaFormatter, err := spec.chromaFormatterFromOptions(opts) - if err != nil { - t.Fatalf("[%d] chromaFormatterFromOptions failed: %s", i, err) - } - - this.assert(formatterChromaInfo(chromaFormatter.(*html.Formatter))) - } -} - -func TestHlLinesToRanges(t *testing.T) { - var zero [][2]int - - for _, this := range []struct { - in string - startLine int - expected interface{} - }{ - {"", 1, zero}, - {"1 4", 1, [][2]int{{1, 1}, {4, 4}}}, - {"1 4", 2, [][2]int{{2, 2}, {5, 5}}}, - {"1-4 5-8", 1, [][2]int{{1, 4}, {5, 8}}}, - {" 1 4 ", 1, [][2]int{{1, 1}, {4, 4}}}, - {"1-4 5-8 ", 1, [][2]int{{1, 4}, {5, 8}}}, - {"1-4 5", 1, [][2]int{{1, 4}, {5, 5}}}, - {"4 5-9", 1, [][2]int{{4, 4}, {5, 9}}}, - {" 1 -4 5 - 8 ", 1, true}, - {"a b", 1, true}, - } { - got, err := hlLinesToRanges(this.startLine, this.in) - - if expectErr, ok := this.expected.(bool); ok && expectErr { - if err == nil { - t.Fatal("No error") - } - } else if err != nil { - t.Fatalf("Got error: %s", err) - } else if !reflect.DeepEqual(this.expected, got) { - t.Fatalf("Expected\n%v but got\n%v", this.expected, got) - } - } -} - -func BenchmarkChromaHighlight(b *testing.B) { - c := qt.New(b) - v := viper.New() - - v.Set("pygmentsstyle", "trac") - v.Set("pygmentsuseclasses", false) - v.Set("pygmentsuseclassic", false) - - code := `// GetTitleFunc returns a func that can be used to transform a string to -// title case. -// -// The supported styles are -// -// - "Go" (strings.Title) -// - "AP" (see https://www.apstylebook.com/) -// - "Chicago" (see http://www.chicagomanualofstyle.org/home.html) -// -// If an unknown or empty style is provided, AP style is what you get. -func GetTitleFunc(style string) func(s string) string { - switch strings.ToLower(style) { - case "go": - return strings.Title - case "chicago": - tc := transform.NewTitleConverter(transform.ChicagoStyle) - return tc.Title - default: - tc := transform.NewTitleConverter(transform.APStyle) - return tc.Title - } -} -` - - spec, err := NewContentSpec(v, nil, nil) - c.Assert(err, qt.IsNil) - - for i := 0; i < b.N; i++ { - _, err := spec.Highlight(code, "go", "linenos=inline,hl_lines=8 15-17") - if err != nil { - b.Fatal(err) - } - } -} |