diff options
author | bep <bjorn.erik.pedersen@gmail.com> | 2015-04-15 20:31:05 +0200 |
---|---|---|
committer | bep <bjorn.erik.pedersen@gmail.com> | 2015-04-15 20:31:06 +0200 |
commit | be24457acfd3eb0b798edda36c89632564e981c7 (patch) | |
tree | c5238e125c542496ea6a23b7ef843d93a6c0819d /helpers/pygments.go | |
parent | be540f5b8fb340f1edfb1ed10c11334bbb85927b (diff) |
Add more options to highlight
Fixes #1021
Diffstat (limited to 'helpers/pygments.go')
-rw-r--r-- | helpers/pygments.go | 96 |
1 files changed, 80 insertions, 16 deletions
diff --git a/helpers/pygments.go b/helpers/pygments.go index 8223759c5..74327c6f5 100644 --- 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 +} |