html-syntax-highlight

highlight code within an html file
Index Commits Files Refs README LICENSE
main.go (2413B)
   1 package main
   2 
   3 import (
   4     "bytes"
   5     "github.com/PuerkitoBio/goquery"
   6     "github.com/alecthomas/chroma"
   7     "github.com/alecthomas/chroma/styles"
   8     "github.com/alecthomas/chroma/lexers"
   9     "github.com/alecthomas/chroma/formatters/html"
  10     "io"
  11     "io/ioutil"
  12     "log"
  13     "os"
  14     "regexp"
  15     "strings"
  16     "fmt"
  17 )
  18 
  19 // print CSS needed for colorizing the code parts
  20 func printCSS(w io.Writer, formatter, style string) {
  21     f := html.New(html.WithClasses(true), html.TabWidth(4))
  22 
  23     s := styles.Get(style)
  24     if s == nil {
  25         s = styles.Fallback
  26     }
  27 
  28     println(f.WriteCSS(w, s))
  29 }
  30 
  31 // Highlight some text.
  32 // Lexer, formatter and style may be empty, in which case a best-effort is made.
  33 func Highlight(w io.Writer, source, lexer, formatter, style string) error {
  34     // Determine lexer.
  35     l := lexers.Get(lexer)
  36     if l == nil {
  37         l = lexers.Analyse(source)
  38     }
  39     if l == nil {
  40         l = lexers.Fallback
  41     }
  42     l = chroma.Coalesce(l)
  43 
  44     f := html.New(html.WithClasses(true), html.TabWidth(4))
  45 
  46     // Determine style.
  47     s := styles.Get(style)
  48     if s == nil {
  49         s = styles.Fallback
  50     }
  51 
  52     it, err := l.Tokenise(nil, source)
  53     if err != nil {
  54         return err
  55     }
  56     return f.Format(w, s, it)
  57 }
  58 
  59 func replaceCodeParts(mdFile []byte) (string, error) {
  60     byteReader := bytes.NewReader(mdFile)
  61     doc, err := goquery.NewDocumentFromReader(byteReader)
  62     if err != nil {
  63         return "", err
  64     }
  65 
  66     re := regexp.MustCompile("(<pre><code class=\"language-).*?(\">)")
  67     rp := strings.NewReplacer("<pre><code class=\"language-", "", "\">", "")
  68 
  69     langs := re.FindAllString(string(mdFile), -1)
  70 
  71     // find code-parts via css selector and replace them with highlighted versions
  72     doc.Find("pre").Each(func(i int, s *goquery.Selection) {
  73         lang := rp.Replace(string(langs[i]))
  74 
  75         if lang == "console" {
  76             lang = "bash"
  77         }
  78 
  79         buf := new(bytes.Buffer)
  80 
  81         err = Highlight(buf, s.Text(), lang, "html", "monokai")
  82         if err != nil {
  83             log.Fatal(err)
  84         }
  85 
  86         s.ReplaceWithHtml(string(buf.String()))
  87     })
  88     new, err := doc.Html()
  89     if err != nil {
  90         return "", err
  91     }
  92 
  93     // remove unnecessarily added html tags
  94     new = strings.Replace(new, "<html><head></head><body>", "", 1)
  95 
  96     return new, nil
  97 }
  98 
  99 func main() {
 100     if len(os.Args) != 2 {
 101         log.Fatal("No file name provided")
 102     }
 103 
 104     args := os.Args[1:]
 105     html, err := ioutil.ReadFile(args[0])
 106     if err != nil {
 107         log.Fatal(err)
 108     }
 109 
 110     replaced, err := replaceCodeParts(html)
 111     if err != nil {
 112         log.Fatal(err)
 113     }
 114 
 115     fmt.Println(replaced)
 116     // printCSS(os.Stdout, "html", "gruvbox")
 117 }