turbo-editors/turbo-corepublic Fork 0
v1.0.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

📦 Turbo Core f3ade8d · on v1.0.0 · k33g · 11h ago
class.go · 136 lines · 4.7 KBGo Blame HistoryRaw
  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
// Package syntax colours source code.
//
// It colours the languages every editor built on this library meets whatever it
// is for — TOML, Markdown, JavaScript, HTML, shell scripts, YAML, XML and
// Dockerfiles — and it is the place an editor registers the language it is
// *for*: Turbo Go registers Go, Turbo Rust registers Rust, and neither is known
// here.
//
// Every scanner turns its input into per-line spans the editor can draw, and
// every one of them is deliberately tolerant: text under the cursor is broken
// most of the time it is being typed, and a highlighter that gives up on
// invalid input is a highlighter that flickers off.
//
// Three things make up the extension point. Definition and Register say what a
// language is and teach it to this package; LineScanner and ScanLines are what
// a scanner is written against; and LineIndex is for a scanner that works in
// byte offsets instead, which is what a tokeniser like go/scanner gives you.
//
// A file is recognised by its extension, then by its name — which is how a
// Dockerfile, which has no extension, is found — and failing both by a shebang.
//
// The package depends on theme only for the vocabulary of style keys, so that a
// token class and the colour it resolves to are named in one place.
package syntax

import "rickub.com/turbo-editors/turbo-core/theme"

// Class is what a run of source text is, in colouring terms.
//
// It is deliberately coarser than any one language's token set: the editor
// needs to tell a keyword from a string, not an ADD from a SUB. Most classes
// are shared across languages — a string is a string in all of them — and only
// the last five belong to markup, because nothing in a programming language
// reads as a heading.
//
// The set is fixed. A language registered from outside this package colours
// itself with these classes and no others, which is what lets one theme colour
// every language an editor built on this library will ever learn.
type Class uint8

// The classes a token can fall into.
const (
	// ClassIdentifier is the zero value, so text nothing else claims is drawn
	// as a plain identifier.
	ClassIdentifier Class = iota
	ClassKeyword
	ClassType
	ClassBuiltin
	ClassConstant
	ClassFunction
	ClassString
	ClassChar
	ClassNumber
	ClassComment
	ClassOperator
	ClassPunctuation

	// ClassHeading is a Markdown heading, whole line included.
	ClassHeading
	// ClassTag is an HTML element name, and the angle brackets around it.
	ClassTag
	// ClassAttribute is an HTML attribute's name.
	ClassAttribute
	// ClassEmphasis is Markdown bold or italic text.
	ClassEmphasis
	// ClassLink is a Markdown link or image, both its text and its target.
	ClassLink
)

// styleKeys maps each class onto the theme key that colours it.
var styleKeys = [...]string{
	ClassIdentifier:  theme.KeySyntaxIdentifier,
	ClassKeyword:     theme.KeySyntaxKeyword,
	ClassType:        theme.KeySyntaxType,
	ClassBuiltin:     theme.KeySyntaxBuiltin,
	ClassConstant:    theme.KeySyntaxConstant,
	ClassFunction:    theme.KeySyntaxFunction,
	ClassString:      theme.KeySyntaxString,
	ClassChar:        theme.KeySyntaxChar,
	ClassNumber:      theme.KeySyntaxNumber,
	ClassComment:     theme.KeySyntaxComment,
	ClassOperator:    theme.KeySyntaxOperator,
	ClassPunctuation: theme.KeySyntaxPunctuation,
	ClassHeading:     theme.KeySyntaxHeading,
	ClassTag:         theme.KeySyntaxTag,
	ClassAttribute:   theme.KeySyntaxAttribute,
	ClassEmphasis:    theme.KeySyntaxEmphasis,
	ClassLink:        theme.KeySyntaxLink,
}

// StyleKey returns the theme key that colours this class.
//
//	style := th.Style(syntax.ClassKeyword.StyleKey())
func (c Class) StyleKey() string {
	if int(c) >= len(styleKeys) {
		return theme.KeySyntaxIdentifier
	}
	return styleKeys[c]
}

// String returns the class name, for tests and for debugging.
func (c Class) String() string {
	names := [...]string{
		ClassIdentifier:  "identifier",
		ClassKeyword:     "keyword",
		ClassType:        "type",
		ClassBuiltin:     "builtin",
		ClassConstant:    "constant",
		ClassFunction:    "function",
		ClassString:      "string",
		ClassChar:        "char",
		ClassNumber:      "number",
		ClassComment:     "comment",
		ClassOperator:    "operator",
		ClassPunctuation: "punctuation",
		ClassHeading:     "heading",
		ClassTag:         "tag",
		ClassAttribute:   "attribute",
		ClassEmphasis:    "emphasis",
		ClassLink:        "link",
	}
	if int(c) >= len(names) {
		return "unknown"
	}
	return names[c]
}

// Span is a run of runes on a single line that share one class.
//
// Columns are rune offsets into the line: Start is included, End excluded,
// matching the convention used everywhere else in the editor.
type Span struct {
	Start int
	End   int
	Class Class
}