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
143
144
145
146
147
148
149
150
151
use crateIntent;
// Names this module's prose links to, resolved for rustdoc.
use crateColumn;
/// What a run of source code is, once something has classified it.
///
/// The description carries the classification and never the source, which is
/// the whole of decision `19d7602d` (2026-09-02, option d). An app that browses
/// source already has a lexer; a renderer does not and should not grow one, and
/// three renderers each growing their own would disagree about the same file.
///
/// # Why the app classifies and the renderer colours
///
/// Measured on MNW's source browser, which is the only consumer in the tree.
/// It highlights server-side with syntect and had already reduced syntect's
/// scope space to seven colours held fixed across all 31 themes, because a
/// reader recognises a highlighting palette and re-tinting it per theme costs
/// that recognition to gain nothing. So the classification existed on the app
/// side already: the only question was whether to throw it away at the seam and
/// have each renderer redo it. This is the answer.
///
/// The precedent is `docengine`'s `Emphasis`, which crosses the same seam the
/// same way: `quasi-tui` maps its four flags onto terminal modifiers, a webview
/// maps them onto elements, and neither parses markdown to do it.
///
/// # The eight, and why these eight
///
/// The seven MNW's palette fixes, plus [`Plain`](Self::Plain) for a run nothing
/// claimed. `Plain` is not an absence: a lexer that ran and found ordinary code
/// is saying something a renderer wants, and an `Option<Syntax>` would have made
/// "unclassified" and "not classified yet" one value.
///
/// `#[non_exhaustive]` from the first commit, deliberately. A ninth class is the
/// obvious next request and it must not be a breaking release across three
/// renderers and five apps.
///
/// # What it is not
///
/// A token type in a grammar. These are display classes, coarse on purpose:
/// the distinctions a reader uses at a glance, not the ones a parser makes.
/// A renderer wanting more has `language` on the node beside this and may do
/// whatever it likes with it.
/// What one line of a diff is: added, removed, or neither.
///
/// The other half of decision `19d7602d`. A diff is a table of lines and the
/// only thing the vocabulary was missing was a way for a line to say which side
/// of the change it is on, so this rides on [`Column`] rather than arriving as a
/// `Node::Diff` carrying git's data model.
///
/// # Why three and not two
///
/// [`Context`](Self::Context) is a line that did not change, and it is most of
/// a diff. Said as `Option<Change>` with `None` for context, a renderer could
/// not tell an unchanged line from a line nobody marked, which is the same
/// argument [`Syntax::Plain`] makes one type up.
///
/// `#[non_exhaustive]` for [`Syntax`]'s reason. A fourth kind -- a moved line, a
/// conflict side -- is a plausible request and must not be a breaking release.