URI: 
       Add more options to highlight - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit be24457acfd3eb0b798edda36c89632564e981c7
   DIR parent be540f5b8fb340f1edfb1ed10c11334bbb85927b
  HTML Author: bep <bjorn.erik.pedersen@gmail.com>
       Date:   Wed, 15 Apr 2015 20:31:05 +0200
       
       Add more options to highlight
       
       Fixes #1021
       
       Diffstat:
         M docs/content/extras/highlighting.md |      26 ++++++++++++++++++--------
         M helpers/pygments.go                 |      96 ++++++++++++++++++++++++++------
         A helpers/pygments_test.go            |      42 +++++++++++++++++++++++++++++++
         M tpl/template_embedded.go            |       8 +++++++-
         M tpl/template_funcs.go               |       4 ++--
       
       5 files changed, 149 insertions(+), 27 deletions(-)
       ---
   DIR diff --git a/docs/content/extras/highlighting.md b/docs/content/extras/highlighting.md
       @@ -44,9 +44,6 @@ Highlighting is carried out via the in-built shortcode `highlight`. `highlight` 
        closing shortcode.
        
        ### Example
       -If you want to highlight code, you need to either fence the code with ``` according to GitHub Flavored Markdown or preceed each line with 4 spaces to identify each line as a line of code.
       -
       -Not doing either will result in the text being rendered as HTML. This will prevent Pygments highlighting from working.
        
        ```
        {{</* highlight html */>}}
       @@ -72,15 +69,28 @@ Not doing either will result in the text being rendered as HTML. This will preve
              <span style="color: #f92672">&lt;/div&gt;</span>
            <span style="color: #f92672">&lt;/section&gt;</span>
        
       +### Options
       +
       +Options to control highlighting can be added as a quoted, comma separated key-value list as the second argument in the shortcode. The example below will highlight as language `go` with inline line numbers, with line number 2 and 3 highlighted.
       +
       +```
       +{{</* highlight go "linenos=inline,hl_lines=2 3" */>}}
       +var a string
       +var b string
       +var c string
       +var d string
       +{{</* / highlight */>}}
       +```
       +
       +Supported keywords:  `style`, `encoding`, `noclasses`, `hl_lines`, `linenos`. Note that `style` and `noclasses` will override the similar setting in the global config.
       +
       +The keywords are the same you would using with Pygments from the command line, see the [Pygments doc](http://pygments.org/docs/) for more info.
       +
        
        ### Disclaimers
        
       - * **Warning:** Pygments is relatively slow. Expect much longer build times when using server-side highlighting.
       + * Pygments is relatively slow, but Hugo will cache the results to disk.
         * Languages available depends on your Pygments installation.
       - * We have sought to have the simplest interface possible, which consequently
       -limits configuration. An ambitious user is encouraged to extend the current
       -functionality to offer more customization.
       -
        
        ## Client-side
        
   DIR diff --git a/helpers/pygments.go b/helpers/pygments.go
       @@ -17,15 +17,15 @@ import (
                "bytes"
                "crypto/sha1"
                "fmt"
       +        "github.com/spf13/hugo/hugofs"
       +        jww "github.com/spf13/jwalterweatherman"
       +        "github.com/spf13/viper"
                "io"
                "io/ioutil"
                "os/exec"
                "path/filepath"
       +        "sort"
                "strings"
       -
       -        "github.com/spf13/hugo/hugofs"
       -        jww "github.com/spf13/jwalterweatherman"
       -        "github.com/spf13/viper"
        )
        
        const pygmentsBin = "pygmentize"
       @@ -40,30 +40,30 @@ func HasPygments() bool {
        }
        
        // Highlight takes some code and returns highlighted code.
       -func Highlight(code string, lexer string) string {
       +func Highlight(code, lang, optsStr string) string {
        
                if !HasPygments() {
                        jww.WARN.Println("Highlighting requires Pygments to be installed and in the path")
                        return code
                }
        
       -        fs := hugofs.OsFs
       -
       -        style := viper.GetString("PygmentsStyle")
       +        options, err := parsePygmentsOpts(optsStr)
        
       -        noclasses := "true"
       -        if viper.GetBool("PygmentsUseClasses") {
       -                noclasses = "false"
       +        if err != nil {
       +                jww.ERROR.Print(err.Error())
       +                return code
                }
        
                // Try to read from cache first
                hash := sha1.New()
       -        io.WriteString(hash, lexer)
                io.WriteString(hash, code)
       -        io.WriteString(hash, style)
       -        io.WriteString(hash, noclasses)
       +        io.WriteString(hash, lang)
       +        io.WriteString(hash, options)
        
                cachefile := filepath.Join(viper.GetString("CacheDir"), fmt.Sprintf("pygments-%x", hash.Sum(nil)))
       +
       +        fs := hugofs.OsFs
       +
                exists, err := Exists(cachefile, fs)
                if err != nil {
                        jww.ERROR.Print(err.Error())
       @@ -89,8 +89,7 @@ func Highlight(code string, lexer string) string {
                var out bytes.Buffer
                var stderr bytes.Buffer
        
       -        cmd := exec.Command(pygmentsBin, "-l"+lexer, "-fhtml", "-O",
       -                fmt.Sprintf("style=%s,noclasses=%s,encoding=utf8", style, noclasses))
       +        cmd := exec.Command(pygmentsBin, "-l"+lang, "-fhtml", "-O", options)
                cmd.Stdin = strings.NewReader(code)
                cmd.Stdout = &out
                cmd.Stderr = &stderr
       @@ -107,3 +106,68 @@ func Highlight(code string, lexer string) string {
        
                return out.String()
        }
       +
       +var pygmentsKeywords = make(map[string]bool)
       +
       +func init() {
       +        pygmentsKeywords["style"] = true
       +        pygmentsKeywords["encoding"] = true
       +        pygmentsKeywords["noclasses"] = true
       +        pygmentsKeywords["hl_lines"] = true
       +        pygmentsKeywords["linenos"] = true
       +}
       +
       +func parsePygmentsOpts(in string) (string, error) {
       +
       +        in = strings.Trim(in, " ")
       +
       +        style := viper.GetString("PygmentsStyle")
       +
       +        noclasses := "true"
       +        if viper.GetBool("PygmentsUseClasses") {
       +                noclasses = "false"
       +        }
       +
       +        if len(in) == 0 {
       +                return fmt.Sprintf("style=%s,noclasses=%s,encoding=utf8", style, noclasses), nil
       +        }
       +
       +        options := make(map[string]string)
       +
       +        o := strings.Split(in, ",")
       +        for _, v := range o {
       +                keyVal := strings.Split(v, "=")
       +                key := strings.ToLower(strings.Trim(keyVal[0], " "))
       +                if len(keyVal) != 2 || !pygmentsKeywords[key] {
       +                        return "", fmt.Errorf("invalid Pygments option: %s", key)
       +                }
       +                options[key] = keyVal[1]
       +        }
       +
       +        if _, ok := options["style"]; !ok {
       +                options["style"] = style
       +        }
       +
       +        if _, ok := options["noclasses"]; !ok {
       +                options["noclasses"] = noclasses
       +        }
       +
       +        if _, ok := options["encoding"]; !ok {
       +                options["encoding"] = "utf8"
       +        }
       +
       +        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, nil
       +}
   DIR diff --git a/helpers/pygments_test.go b/helpers/pygments_test.go
       @@ -0,0 +1,42 @@
       +package helpers
       +
       +import (
       +        "github.com/spf13/viper"
       +        "testing"
       +)
       +
       +func TestParsePygmentsArgs(t *testing.T) {
       +        for i, this := range []struct {
       +                in                 string
       +                pygmentsStyle      string
       +                pygmentsUseClasses bool
       +                expect1            interface{}
       +        }{
       +                {"", "foo", true, "style=foo,noclasses=false,encoding=utf8"},
       +                {"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},
       +        } {
       +                viper.Set("PygmentsStyle", this.pygmentsStyle)
       +                viper.Set("PygmentsUseClasses", this.pygmentsUseClasses)
       +
       +                result1, err := parsePygmentsOpts(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)
       +                        }
       +
       +                }
       +        }
       +}
   DIR diff --git a/tpl/template_embedded.go b/tpl/template_embedded.go
       @@ -21,7 +21,13 @@ type Tmpl struct {
        func (t *GoHTMLTemplate) EmbedShortcodes() {
                t.AddInternalShortcode("ref.html", `{{ .Get 0 | ref .Page }}`)
                t.AddInternalShortcode("relref.html", `{{ .Get 0 | relref .Page }}`)
       -        t.AddInternalShortcode("highlight.html", `{{ .Get 0 | highlight .Inner  }}`)
       +        t.AddInternalShortcode("highlight.html", `
       +        {{ if len .Params | eq 2 }}
       +        {{ highlight .Inner (.Get 0) (.Get 1) }}
       +        {{ else }}
       +        {{ highlight .Inner (.Get 0) "" }}
       +        {{ end }}
       +        `)
                t.AddInternalShortcode("test.html", `This is a simple Test`)
                t.AddInternalShortcode("figure.html", `<!-- image -->
        <figure {{ with .Get "class" }}class="{{.}}"{{ end }}>
   DIR diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
       @@ -875,7 +875,7 @@ func ReturnWhenSet(a, k interface{}) interface{} {
                return ""
        }
        
       -func Highlight(in interface{}, lang string) template.HTML {
       +func Highlight(in interface{}, lang, opts string) template.HTML {
                var str string
                av := reflect.ValueOf(in)
                switch av.Kind() {
       @@ -883,7 +883,7 @@ func Highlight(in interface{}, lang string) template.HTML {
                        str = av.String()
                }
        
       -        return template.HTML(helpers.Highlight(html.UnescapeString(str), lang))
       +        return template.HTML(helpers.Highlight(html.UnescapeString(str), lang, opts))
        }
        
        var markdownTrimPrefix = []byte("<p>")