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

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

languages.md · 283 lines · 15.2 KBmarkdown Blame HistoryRaw
📦 Turbo Rust 713ea5c k33g 10h ago1# Reference: languages coloured
2
3> Neutral description of which files Turbo Rust colours, how it decides, and what each scanner recognises.
4
5## Recognition
6
7A file's **extension** decides whenever it is one of these:
8
9| Extension | Language |
10| --- | --- |
11| `.rs` | Rust |
12| `.toml` | TOML |
13| `.yaml`, `.yml` | YAML |
14| `.md`, `.markdown` | Markdown |
15| `.js`, `.mjs`, `.cjs` | JavaScript |
16| `.html`, `.htm` | HTML |
17| `.xml`, `.xsd`, `.xsl`, `.xslt`, `.svg`, `.plist`, `.csproj`, `.pom` | XML |
18| `.sh`, `.bash`, `.zsh` | Shell |
19| `.dockerfile`, `.containerfile` | Dockerfile |
20
21Extensions are matched case-insensitively, and only the last one counts: `main.rs.backup` is not Rust.
22
23A file whose extension decides nothing is looked up by **name** next. Only files that carry no useful extension need this:
24
25| Name | Language |
26| --- | --- |
27| `Dockerfile`, `Containerfile` | Dockerfile |
28
29A name matches on the whole of it or on the part before the first dot, ignoring case — so `Dockerfile`, `dockerfile` and `Dockerfile.dev` are all recognised, while `Dockerfile.md` is Markdown, because the extension is consulted first.
30
31A file that neither table claims is a **shell script** when its first line is a shebang naming a shell — `sh`, `bash`, `zsh`, `dash` or `ksh`, as a path element or as the argument to `env`. That is what colours `configure`, a git hook, or a script somebody renamed.
32
33| First line | Result |
34| --- | --- |
35| `#!/bin/sh` | Shell |
36| `#!/usr/bin/env bash` | Shell |
37| `#!/usr/bin/env -S bash -e` | Shell |
38| `#!/usr/bin/env python3` | Not coloured |
39| Anything not starting `#!` | Not coloured |
40
41The order is fixed — extension, then name, then first line — and the first to decide wins: a `.rs` file starting with a shebang is Rust.
42
43Everything else is shown in plain text. That is not an error — opening a PNG in the editor is not a mistake, it is just not coloured.
44
45## Classes
46
47Every scanner produces the same vocabulary of classes, and each maps to one theme key.
48
49| Class | Theme key | Produced by |
50| --- | --- | --- |
51| `identifier` | `syntax.identifier` | Rust, TOML, JavaScript, shell, YAML, Dockerfile |
52| `keyword` | `syntax.keyword` | Rust, JavaScript, shell, HTML (doctype), XML, Dockerfile |
53| `type` | `syntax.type` | Rust, TOML (table headers), YAML (tags) |
54| `builtin` | `syntax.builtin` | Rust, JavaScript, shell (builtins and expansions), YAML (anchors and aliases), Dockerfile (variables) |
55| `constant` | `syntax.constant` | Rust, TOML, JavaScript, shell, YAML, HTML and XML (entities) |
56| `function` | `syntax.function` | Rust, JavaScript, shell (the command) |
57| `string` | `syntax.string` | all |
58| `char` | `syntax.char` | Rust |
59| `number` | `syntax.number` | Rust, TOML, JavaScript, shell, YAML, Dockerfile |
60| `comment` | `syntax.comment` | Rust, TOML, JavaScript, shell, HTML, YAML, XML, Dockerfile |
61| `operator` | `syntax.operator` | Rust, TOML, JavaScript, shell, HTML, YAML (block scalar headers), XML, Dockerfile |
62| `punctuation` | `syntax.punctuation` | Rust, TOML, JavaScript, shell, Markdown, YAML, Dockerfile |
63| `heading` | `syntax.heading` | Markdown |
64| `tag` | `syntax.tag` | HTML, XML |
65| `attribute` | `syntax.attribute` | HTML, XML, Dockerfile (flags) |
66| `emphasis` | `syntax.emphasis` | Markdown |
67| `link` | `syntax.link` | Markdown |
68
69## Rust
70
71Hand-written, in `internal/rustlang`. Three constructs cross a line break and are carried exactly rather than guessed at: a block comment (with its nesting depth), a raw string (with its hash count), and an ordinary string.
72
73| Recognised | As |
74| --- | --- |
75| `fn`, `let`, `impl`, `struct`, `enum`, `trait`, `match`, `pub`, `mut`, `async`, `await`, `unsafe`, … | keyword |
76| the words reserved for future use — `become`, `priv`, `typeof`, `unsized`, … | keyword |
77| `bool`, `char`, `str`, `i8``i128`, `u8``u128`, `isize`, `usize`, `f32`, `f64`, `self`, `Self` | type |
78| any other name starting with a capital | type |
79| `true`, `false`, `None`, `Some`, `Ok`, `Err` | constant |
80| a name immediately before `(` | function |
81| `name!`, the `!` included | builtin |
82| `#[derive(Debug)]`, `#![no_std]` | attribute |
83| `"…"`, `b"…"`, across lines, escapes honoured | string |
84| `r"…"`, `r#"…"#`, `br##"…"##`, across lines | string |
85| `'x'`, `'\n'`, `'\u{1F600}'`, `b'x'` | char |
86| `'a`, `'static` | type |
87| `42`, `1_000`, `0xFF`, `0b1010`, `0o77`, `1.5e-3`, `42u8`, `3.0f64` | number |
88| `//`, `///`, `//!` to end of line | comment |
89| `/* … */`, **nested**, across lines | comment |
90| `..`, `..=` | operator |
91| `:`, `::` | punctuation |
92| runs of `+-*/%=<>!&\|^~?` | operator |
93| `()[]{},;.` | punctuation |
94
95**A lifetime is told from a character literal by looking for the closing quote** where a character would have to put it — one rune along, or further for an escape. `'a` is a lifetime, `'a'` is a character, `'static` is a lifetime, `'\u{1F600}'` is a character. Getting this wrong strings the rest of the line, which is why it has tests of its own.
96
97**A lifetime is coloured as a type**, because it is a generic parameter, declared and used in the same places one is.
98
99**A capital letter means a type.** Rust's naming convention is strong enough to lean on: a type, a trait and an enum variant are all `UpperCamelCase` and nothing else is. A constant in `SCREAMING_SNAKE_CASE` is coloured as a type by this rule, which is the one place it is visibly a heuristic.
100
101**`None`, `Some`, `Ok` and `Err` are Option's and Result's, not the language's.** They are coloured as constants because a reader meets them before any other variant and reads them as they read `true`.
102
103**Macros take their `!`.** `println!` is one span; `a != b` is not a macro, and the two are told apart by the `=` that follows.
104
105**A number takes its suffix.** `42u8` is one literal, and colouring the `u8` as a type would split a thing that is not two things.
106
107**An attribute that runs past the end of its line is coloured to the end and not carried.** Unlike a comment or a string, an unclosed attribute is nearly always a half-typed one, and carrying it would paint the rest of the file.
108
109**Not recognised**, each for a stated reason:
110
111| Not recognised | Because |
112| --- | --- |
113| Which macro is being invoked | `println!` and a macro you wrote yourself are both builtins; telling them apart needs the crate's expansion |
114| The inside of a macro body | `macro_rules!` bodies are coloured as ordinary Rust, which is usually right and sometimes not |
115| `SCREAMING_SNAKE_CASE` constants as constants | Indistinguishable from a type name by the leading-capital rule, and a second rule for it would mis-colour a type whose name is an acronym |
116| Doc-comment Markdown | A `///` comment is one comment, not a Markdown document |
117
118## TOML
119
120| Recognised | As |
121| --- | --- |
122| `# comment` | comment |
123| `[table]`, `[[array]]` | the name as a type, the brackets as punctuation |
124| `key =` | identifier, then operator |
125| `"basic"`, `'literal'`, `"""multi-line"""`, `'''multi-line'''` | string |
126| `true`, `false` | constant |
127| numbers, dates, times, `inf`, `nan` | number |
128
129## YAML
130
131A compose file, a Kubernetes manifest and a CI workflow are all this: there is no separate dialect, because a dialect would be somebody else's schema to keep in step with.
132
133| Recognised | As |
134| --- | --- |
135| `# comment` | comment |
136| `key:` before a space or the end of the line | the key as an identifier, the colon as punctuation |
137| `"quoted": 1`, `'quoted': 1` | the quoted key as an identifier |
138| `- ` opening a sequence entry | punctuation |
139| `"…"`, `'…'` | string |
140| `true`, `false`, `yes`, `no`, `on`, `off`, `null` | constant, whatever their case |
141| numbers, dates and times written without quotes | number |
142| `&anchor`, `*alias` | builtin |
143| `!!str`, `!Custom` | type |
144| `---`, `...` | the whole line as punctuation |
145| `{`, `}`, `[`, `]`, `,` | punctuation |
146| `\|`, `>`, with their chomping and indentation indicators | the header as an operator, the body as a string |
147
148**A colon is a separator only when a space or the end of the line follows it.** `image: nginx:1.27` is a key and one value, and `url: http://example.com/x` is a key and one URL — colouring the inner colons as separators would put every image tag and every URL in three colours.
149
150**A block scalar's extent is decided by indentation**, not by a delimiter. The first content line after `|` or `>` fixes the block's indentation; every line indented at least that far belongs to it, and the first line that is not ends it. **A blank line inside a block stays inside it**: a literal scalar keeps its empty lines, and ending the block at the first paragraph break would cut a shell script in a CI file in half.
151
152**A `#` needs a space before it to start a comment**, so `colour: ff#00aa` is one scalar.
153
154| Not recognised | Because |
155| --- | --- |
156| The schema of a compose file, a manifest or a workflow | Colouring `services:` differently from any other key means carrying somebody else's schema, and it goes stale the day they add a key |
157| Multi-document streams as separate documents | `---` is coloured, but nothing is reset at it; nothing in the colouring depends on document boundaries |
158| Whether a bare word is a string or a number to a parser | `1.2.3` is a version to a reader and a string to YAML; the scanner colours what it looks like |
159
160## Markdown
161
162| Recognised | As |
163| --- | --- |
164| `# Heading``###### Heading` | the whole line as a heading |
165| `**bold**`, `__bold__`, `*italic*`, `_italic_` | emphasis |
166| `` `code` `` | string |
167| `[text](target)`, `![alt](src)` | the whole thing as a link |
168| `- `, `* `, `+ `, `1. `, `1) ` | the marker as punctuation |
169| `>` | punctuation |
170| `---`, `***`, `___` | punctuation |
171| ` ``` ` and `~~~` fences | the whole block, opening and closing lines included, as a string |
172
173A fenced block is **one colour whatever language it announces**: ```` ```rust ```` does not colour its contents as Rust. The run of markers that opens a block must be matched by the same character to close it, so a backtick fence is not closed by a tilde one. An unclosed fence colours to the end of the file.
174
175The run of markers opening emphasis must be matched by a run of the same length, so `**bold**` is one span rather than two italics.
176
177## JavaScript
178
179| Recognised | As |
180| --- | --- |
181| `const`, `let`, `function`, `class`, `async`, `await`, `import`, `export`, … | keyword |
182| `true`, `false`, `null`, `undefined`, `NaN`, `Infinity`, `this` | constant |
183| `console`, `document`, `window`, `Array`, `Object`, `Promise`, `Math`, `JSON`, … | builtin |
184| a name immediately before `(` | function |
185| `"…"`, `'…'` | string |
186| `` `` ``, interpolations included, across lines | string |
187| `//` to end of line, `/* … */` across lines | comment |
188| `42`, `3.14`, `0x1f`, `0b1010`, `0o777`, `1_000_000`, `1e6`, `10n` | number |
189| runs of `+-*/%=<>!&|^~?:` | operator |
190| `()[]{},;.` | punctuation |
191
192**Regular-expression literals are not recognised.** Telling `/x/g` from a division needs to know whether the previous token could end an expression; a wrong guess colours the rest of a line as a string, which is worse than leaving a regex the colour of an operator.
193
194Globals are recognised by name, so a file that shadows `Math` still has it coloured as a builtin — the same rule Rust's primitive types follow.
195
196## HTML
197
198| Recognised | As |
199| --- | --- |
200| `<tag`, `</tag`, `>`, `/>` | tag |
201| attribute names, including `data-*`, `xlink:href`, `@click`, `v-bind.prop` | attribute |
202| `=` | operator |
203| `"…"`, `'…'` | string |
204| `<!-- … -->`, across lines | comment |
205| `&amp;`, `&#169;` | constant |
206| `<!DOCTYPE …>` and other declarations | keyword |
207
208Text between tags is not coloured. A bare `&` with no `;` within 32 characters is left alone, because it is legal text.
209
210**The contents of `<script>` and `<style>` are not coloured** as JavaScript and CSS.
211
212## XML
213
214Its own scanner rather than HTML's, for one reason that matters: CDATA. The whole point of `<![CDATA[ … ]]>` is that its contents are *not* markup, and colouring the tags inside one as tags is exactly backwards.
215
216| Recognised | As |
217| --- | --- |
218| `<?xml version="1.0"?>` and other processing instructions | the target and `?>` as keyword, the pairs between as attributes and strings |
219| `<!DOCTYPE …>` and the other `<!` forms | keyword |
220| `<!-- … -->`, across lines | comment |
221| `<![CDATA[ … ]]>`, across lines | string |
222| `<tag`, `</tag`, `>`, `/>` | tag |
223| `<ns:tag>`, `xsi:type` | the prefix and the local name as **one** span |
224| attribute names | attribute |
225| `=` | operator |
226| `"…"`, `'…'` | string |
227| `&amp;`, `&#169;` | constant |
228
229**A comment and a CDATA section close on different delimiters**, and are carried separately: a `-->` inside a CDATA section does not end it.
230
231**A bare `&` with no semicolon within 32 characters is left alone**, because it is legal text in plenty of documents and swallowing the rest of the line would be the bigger mistake.
232
233Text between tags is not coloured.
234
235## Shell
236
237Applies to `sh`, `bash` and `zsh` alike: the keywords recognised are the ones they share.
238
239| Recognised | As |
240| --- | --- |
241| `if`, `then`, `fi`, `for`, `while`, `case`, `esac`, `function`, `return`, … | keyword |
242| `true`, `false` | constant |
243| `echo`, `printf`, `export`, `local`, `read`, `cd`, `set`, `source`, … | builtin |
244| `$NAME`, `${…}`, `$(…)`, `$1`, `$?`, `$@` | builtin |
245| the **first bare word on a line** | function |
246| every later bare word, and `NAME` in `NAME=value` | identifier |
247| `'…'`, with nothing escaped or expanded inside | string |
248| `"…"`, with the expansions inside it coloured as expansions | string |
249| `#` to end of line | comment |
250
251`$(a $(b) c)` is one span: nesting is counted. An option such as `-euo` is one word, not a minus and a word.
252
253**Heredocs are not recognised.** `<<EOF` and the text after it are coloured as ordinary shell.
254
255## Dockerfile
256
257| Recognised | As |
258| --- | --- |
259| `FROM`, `RUN`, `COPY`, `ADD`, `ARG`, `ENV`, `CMD`, `ENTRYPOINT`, `EXPOSE`, `LABEL`, `USER`, `VOLUME`, `WORKDIR`, `HEALTHCHECK`, `ONBUILD`, `SHELL`, `STOPSIGNAL`, `MAINTAINER` | keyword, in any case |
260| `AS`, `NONE` | keyword |
261| `# comment`, including the `# syntax=` and `# escape=` directives | comment |
262| `--from=builder`, `--chown=me:me` | the flag name as an attribute |
263| `$NAME`, `${NAME}`, `${NAME:-default}` | builtin, as one span to the closing brace |
264| `"…"`, `'…'` | string |
265| a trailing `\` | operator |
266| numbers | number |
267| paths and image references — `/usr/local/bin`, `golang:1.26-alpine` | identifier, as **one** span |
268
269**Only the first word of a line can be an instruction**, and a word that is not one is an argument — which is what keeps a continuation line's first word out of the keyword colour.
270
271**Nothing crosses a line break.** A `\` joins two lines for Docker, but each half still reads as a command and is coloured on its own.
272
273| Not recognised | Because |
274| --- | --- |
275| The shell inside a `RUN` | It would mean running the shell scanner over part of a line and mapping its columns out, and `RUN` may hold any language |
276| Heredocs in a `RUN` | The same reason the shell scanner does not recognise them |
277| Which stage a `--from` names | Nothing here reads the rest of the file |
278
279## See also
280
281- [Theme file format](themes.md) — every key these classes resolve to
282- [Colouring and completion](../explanation/colouring-and-completion.md) — why the scanners are written this way
283- [How to write your own theme](../how-to/write-a-theme.md)