summaryrefslogtreecommitdiffstats
path: root/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'helpers')
-rw-r--r--helpers/content.go45
-rw-r--r--helpers/general.go27
-rw-r--r--helpers/general_test.go13
-rw-r--r--helpers/pygments.go402
-rw-r--r--helpers/pygments_test.go300
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">&#34;Hello&#34;</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)
- }
- }
-}