summaryrefslogtreecommitdiffstats
path: root/helpers/pygments.go
diff options
context:
space:
mode:
authorbep <bjorn.erik.pedersen@gmail.com>2015-04-15 20:31:05 +0200
committerbep <bjorn.erik.pedersen@gmail.com>2015-04-15 20:31:06 +0200
commitbe24457acfd3eb0b798edda36c89632564e981c7 (patch)
treec5238e125c542496ea6a23b7ef843d93a6c0819d /helpers/pygments.go
parentbe540f5b8fb340f1edfb1ed10c11334bbb85927b (diff)
Add more options to highlight
Fixes #1021
Diffstat (limited to 'helpers/pygments.go')
-rw-r--r--helpers/pygments.go96
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
+}