forked from benrowe/books
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcode_highlight.go
142 lines (125 loc) · 3.46 KB
/
code_highlight.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"path"
"time"
"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/formatters/html"
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/kjk/u"
)
var (
htmlFormatter *html.Formatter
highlightStyle *chroma.Style
)
// CodeBlockInfo represents info about code snippet
type CodeBlockInfo struct {
Lang string
GitHubURI string
PlaygroundURI string
}
func init() {
htmlFormatter = html.New(html.WithClasses(), html.TabWidth(2))
u.PanicIf(htmlFormatter == nil, "couldn't create html formatter")
styleName := "monokailight"
highlightStyle = styles.Get(styleName)
u.PanicIf(highlightStyle == nil, "didn't find style '%s'", styleName)
}
// gross hack: we need to change html generated by chroma
func fixupHTMLCodeBlock(htmlCode string, info *CodeBlockInfo) string {
classLang := ""
if info.Lang != "" {
classLang = " lang-" + info.Lang
}
if info.GitHubURI == "" && info.PlaygroundURI == "" {
html := fmt.Sprintf(`
<div class="code-box%s">
<div>
%s
</div>
</div>`, classLang, htmlCode)
return html
}
playgroundPart := ""
if info.PlaygroundURI != "" {
playgroundPart = fmt.Sprintf(`
<div class="code-box-playground">
<a href="%s" target="_blank">try online</a>
</div>
`, info.PlaygroundURI)
}
gitHubPart := ""
if info.GitHubURI != "" {
// gitHubLoc is sth. like github.com/essentialbooks/books/books/go/main.go
fileName := path.Base(info.GitHubURI)
gitHubPart = fmt.Sprintf(`
<div class="code-box-github">
<a href="%s" target="_blank">%s</a>
</div>`, info.GitHubURI, fileName)
}
html := fmt.Sprintf(`
<div class="code-box%s">
<div>
%s
</div>
<div class="code-box-nav">
%s
%s
</div>
</div>`, classLang, htmlCode, playgroundPart, gitHubPart)
return html
}
// based on https://github.com/alecthomas/chroma/blob/master/quick/quick.go
func htmlHighlight2(w io.Writer, source, lang, defaultLang string) error {
if lang == "" {
lang = defaultLang
}
l := lexers.Get(lang)
if l == nil {
l = lexers.Analyse(source)
}
if l == nil {
l = lexers.Fallback
}
l = chroma.Coalesce(l)
it, err := l.Tokenise(nil, source)
if err != nil {
return err
}
return htmlFormatter.Format(w, highlightStyle, it)
}
func htmlHighlight(w io.Writer, source, lang, defaultLang string) error {
ch := make(chan error, 1)
go func() {
err := htmlHighlight2(w, source, lang, defaultLang)
ch <- err
}()
reportOvertime := func() {
ioutil.WriteFile("hili_hang.txt", []byte(source), 0644)
logf("Too long processing lang: %s, defaultLang: %s, source:\n%s\n\n", lang, defaultLang, source)
ch <- nil
}
timer := time.AfterFunc(time.Second*5, reportOvertime)
defer timer.Stop()
err := <-ch
return err
}
func testHang() {
//d, err := ioutil.ReadFile("hili_hang.txt")
//must(err)
// s := string(d)
s := `// 64-bit floats have 53 digits of precision, including the whole-number-part.
double a = 0011111110111001100110011001100110011001100110011001100110011010; // imperfect representation of 0.1
double b = 0011111111001001100110011001100110011001100110011001100110011010; // imperfect representation of 0.2
double c = 0011111111010011001100110011001100110011001100110011001100110011; // imperfect representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; // Note that this is not quite equal to the "canonical" 0.3!a
`
for i := 0; i < 1024*32; i++ {
var buf bytes.Buffer
htmlHighlight(&buf, s, "C++", "")
}
}