highlight_decl.go

v1.3.4
Doc Versions Source
1
package godoc
2
3
import (
4
	"go/scanner"
5
	"go/token"
6
	"html"
7
	"strings"
8
)
9
10
// HighlightDecl returns syntax-highlighted HTML for a Go declaration snippet.
11
// Unlike HighlightGo, this produces inline HTML without table/line-number wrapping.
12
func HighlightDecl(src string) string {
13
	// Wrap in a minimal package context so the scanner accepts it.
14
	prefix := "package p\n"
15
	full := []byte(prefix + src)
16
17
	fset := token.NewFileSet()
18
	file := fset.AddFile("", fset.Base(), len(full))
19
20
	var s scanner.Scanner
21
	s.Init(file, full, nil, scanner.ScanComments)
22
23
	type span struct {
24
		offset int
25
		end    int
26
		class  string
27
	}
28
	var spans []span
29
30
	for {
31
		pos, tok, lit := s.Scan()
32
		if tok == token.EOF {
33
			break
34
		}
35
36
		offset := int(pos) - file.Base()
37
		if offset < len(prefix) {
38
			continue // skip the synthetic "package p\n"
39
		}
40
41
		var class string
42
		var length int
43
44
		switch {
45
		case tok == token.COMMENT:
46
			class = "com"
47
			length = len(lit)
48
		case tok == token.STRING || tok == token.CHAR:
49
			class = "str"
50
			length = len(lit)
51
		case tok == token.INT || tok == token.FLOAT || tok == token.IMAG:
52
			class = "num"
53
			length = len(lit)
54
		case tok.IsKeyword():
55
			class = "kw"
56
			length = len(tok.String())
57
		case tok == token.IDENT:
58
			if isBuiltin(lit) {
59
				class = "bi"
60
				length = len(lit)
61
			}
62
		}
63
64
		if class != "" {
65
			spans = append(spans, span{
66
				offset: offset - len(prefix), // adjust to src-relative
67
				end:    offset - len(prefix) + length,
68
				class:  class,
69
			})
70
		}
71
	}
72
73
	var b strings.Builder
74
	pos := 0
75
	for _, sp := range spans {
76
		if sp.offset < 0 {
77
			continue
78
		}
79
		start := sp.offset
80
		end := sp.end
81
		if end > len(src) {
82
			end = len(src)
83
		}
84
		if start > pos {
85
			b.WriteString(html.EscapeString(src[pos:start]))
86
		}
87
		b.WriteString(`<span class="`)
88
		b.WriteString(sp.class)
89
		b.WriteString(`">`)
90
		b.WriteString(html.EscapeString(src[start:end]))
91
		b.WriteString(`</span>`)
92
		pos = end
93
	}
94
	if pos < len(src) {
95
		b.WriteString(html.EscapeString(src[pos:]))
96
	}
97
98
	return b.String()
99
}
100

Source Files