# Reference: languages coloured > Neutral description of which files Turbo Rust colours, how it decides, and what each scanner recognises. ## Recognition A file's **extension** decides whenever it is one of these: | Extension | Language | | --- | --- | | `.rs` | Rust | | `.toml` | TOML | | `.yaml`, `.yml` | YAML | | `.md`, `.markdown` | Markdown | | `.js`, `.mjs`, `.cjs` | JavaScript | | `.html`, `.htm` | HTML | | `.xml`, `.xsd`, `.xsl`, `.xslt`, `.svg`, `.plist`, `.csproj`, `.pom` | XML | | `.sh`, `.bash`, `.zsh` | Shell | | `.dockerfile`, `.containerfile` | Dockerfile | Extensions are matched case-insensitively, and only the last one counts: `main.rs.backup` is not Rust. A file whose extension decides nothing is looked up by **name** next. Only files that carry no useful extension need this: | Name | Language | | --- | --- | | `Dockerfile`, `Containerfile` | Dockerfile | A 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. A 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. | First line | Result | | --- | --- | | `#!/bin/sh` | Shell | | `#!/usr/bin/env bash` | Shell | | `#!/usr/bin/env -S bash -e` | Shell | | `#!/usr/bin/env python3` | Not coloured | | Anything not starting `#!` | Not coloured | The order is fixed — extension, then name, then first line — and the first to decide wins: a `.rs` file starting with a shebang is Rust. Everything 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. ## Classes Every scanner produces the same vocabulary of classes, and each maps to one theme key. | Class | Theme key | Produced by | | --- | --- | --- | | `identifier` | `syntax.identifier` | Rust, TOML, JavaScript, shell, YAML, Dockerfile | | `keyword` | `syntax.keyword` | Rust, JavaScript, shell, HTML (doctype), XML, Dockerfile | | `type` | `syntax.type` | Rust, TOML (table headers), YAML (tags) | | `builtin` | `syntax.builtin` | Rust, JavaScript, shell (builtins and expansions), YAML (anchors and aliases), Dockerfile (variables) | | `constant` | `syntax.constant` | Rust, TOML, JavaScript, shell, YAML, HTML and XML (entities) | | `function` | `syntax.function` | Rust, JavaScript, shell (the command) | | `string` | `syntax.string` | all | | `char` | `syntax.char` | Rust | | `number` | `syntax.number` | Rust, TOML, JavaScript, shell, YAML, Dockerfile | | `comment` | `syntax.comment` | Rust, TOML, JavaScript, shell, HTML, YAML, XML, Dockerfile | | `operator` | `syntax.operator` | Rust, TOML, JavaScript, shell, HTML, YAML (block scalar headers), XML, Dockerfile | | `punctuation` | `syntax.punctuation` | Rust, TOML, JavaScript, shell, Markdown, YAML, Dockerfile | | `heading` | `syntax.heading` | Markdown | | `tag` | `syntax.tag` | HTML, XML | | `attribute` | `syntax.attribute` | HTML, XML, Dockerfile (flags) | | `emphasis` | `syntax.emphasis` | Markdown | | `link` | `syntax.link` | Markdown | ## Rust Hand-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. | Recognised | As | | --- | --- | | `fn`, `let`, `impl`, `struct`, `enum`, `trait`, `match`, `pub`, `mut`, `async`, `await`, `unsafe`, … | keyword | | the words reserved for future use — `become`, `priv`, `typeof`, `unsized`, … | keyword | | `bool`, `char`, `str`, `i8`…`i128`, `u8`…`u128`, `isize`, `usize`, `f32`, `f64`, `self`, `Self` | type | | any other name starting with a capital | type | | `true`, `false`, `None`, `Some`, `Ok`, `Err` | constant | | a name immediately before `(` | function | | `name!`, the `!` included | builtin | | `#[derive(Debug)]`, `#![no_std]` | attribute | | `"…"`, `b"…"`, across lines, escapes honoured | string | | `r"…"`, `r#"…"#`, `br##"…"##`, across lines | string | | `'x'`, `'\n'`, `'\u{1F600}'`, `b'x'` | char | | `'a`, `'static` | type | | `42`, `1_000`, `0xFF`, `0b1010`, `0o77`, `1.5e-3`, `42u8`, `3.0f64` | number | | `//`, `///`, `//!` to end of line | comment | | `/* … */`, **nested**, across lines | comment | | `..`, `..=` | operator | | `:`, `::` | punctuation | | runs of `+-*/%=<>!&\|^~?` | operator | | `()[]{},;.` | punctuation | **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. **A lifetime is coloured as a type**, because it is a generic parameter, declared and used in the same places one is. **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. **`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`. **Macros take their `!`.** `println!` is one span; `a != b` is not a macro, and the two are told apart by the `=` that follows. **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. **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. **Not recognised**, each for a stated reason: | Not recognised | Because | | --- | --- | | Which macro is being invoked | `println!` and a macro you wrote yourself are both builtins; telling them apart needs the crate's expansion | | The inside of a macro body | `macro_rules!` bodies are coloured as ordinary Rust, which is usually right and sometimes not | | `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 | | Doc-comment Markdown | A `///` comment is one comment, not a Markdown document | ## TOML | Recognised | As | | --- | --- | | `# comment` | comment | | `[table]`, `[[array]]` | the name as a type, the brackets as punctuation | | `key =` | identifier, then operator | | `"basic"`, `'literal'`, `"""multi-line"""`, `'''multi-line'''` | string | | `true`, `false` | constant | | numbers, dates, times, `inf`, `nan` | number | ## YAML A 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. | Recognised | As | | --- | --- | | `# comment` | comment | | `key:` before a space or the end of the line | the key as an identifier, the colon as punctuation | | `"quoted": 1`, `'quoted': 1` | the quoted key as an identifier | | `- ` opening a sequence entry | punctuation | | `"…"`, `'…'` | string | | `true`, `false`, `yes`, `no`, `on`, `off`, `null` | constant, whatever their case | | numbers, dates and times written without quotes | number | | `&anchor`, `*alias` | builtin | | `!!str`, `!Custom` | type | | `---`, `...` | the whole line as punctuation | | `{`, `}`, `[`, `]`, `,` | punctuation | | `\|`, `>`, with their chomping and indentation indicators | the header as an operator, the body as a string | **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. **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. **A `#` needs a space before it to start a comment**, so `colour: ff#00aa` is one scalar. | Not recognised | Because | | --- | --- | | 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 | | Multi-document streams as separate documents | `---` is coloured, but nothing is reset at it; nothing in the colouring depends on document boundaries | | 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 | ## Markdown | Recognised | As | | --- | --- | | `# Heading` … `###### Heading` | the whole line as a heading | | `**bold**`, `__bold__`, `*italic*`, `_italic_` | emphasis | | `` `code` `` | string | | `[text](target)`, `![alt](src)` | the whole thing as a link | | `- `, `* `, `+ `, `1. `, `1) ` | the marker as punctuation | | `>` | punctuation | | `---`, `***`, `___` | punctuation | | ` ``` ` and `~~~` fences | the whole block, opening and closing lines included, as a string | A 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. The run of markers opening emphasis must be matched by a run of the same length, so `**bold**` is one span rather than two italics. ## JavaScript | Recognised | As | | --- | --- | | `const`, `let`, `function`, `class`, `async`, `await`, `import`, `export`, … | keyword | | `true`, `false`, `null`, `undefined`, `NaN`, `Infinity`, `this` | constant | | `console`, `document`, `window`, `Array`, `Object`, `Promise`, `Math`, `JSON`, … | builtin | | a name immediately before `(` | function | | `"…"`, `'…'` | string | | `` `…` ``, interpolations included, across lines | string | | `//` to end of line, `/* … */` across lines | comment | | `42`, `3.14`, `0x1f`, `0b1010`, `0o777`, `1_000_000`, `1e6`, `10n` | number | | runs of `+-*/%=<>!&|^~?:` | operator | | `()[]{},;.` | punctuation | **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. Globals 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. ## HTML | Recognised | As | | --- | --- | | ``, `/>` | tag | | attribute names, including `data-*`, `xlink:href`, `@click`, `v-bind.prop` | attribute | | `=` | operator | | `"…"`, `'…'` | string | | ``, across lines | comment | | `&`, `©` | constant | | `` and other declarations | keyword | Text between tags is not coloured. A bare `&` with no `;` within 32 characters is left alone, because it is legal text. **The contents of `