turbo-editors/turbo-golopublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-golo.git
git clone ssh://git@rickub.com/turbo-editors/turbo-golo.git

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

languages.md · 294 lines · 17.7 KBmarkdown Blame HistoryRaw
📦 Turbo Golo d710c1b k33g 11h ago1# Reference: languages coloured
2
3> Neutral description of which files Turbo Golo 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| `.golo` | Golo |
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: `notes.golo.md` is Markdown, and `main.golo.backup` is not Golo.
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 read by its **first line**. A shebang naming `golo` makes it Golo: `#` opens a comment in Golo, so the interpreter reads the line as one, and a script installed without its extension and run as a command is Golo and nothing else. A shebang naming a shell — `sh`, `bash`, `zsh`, `dash` or `ksh` — makes it a shell script. The interpreter is recognised as a path element or as the argument to `env`.
32
33| First line | Result |
34| --- | --- |
35| `#!/usr/bin/env golo` | Golo |
36| `#!/usr/local/bin/golo` | Golo |
37| `#!/bin/sh` | Shell |
38| `#!/usr/bin/env bash` | Shell |
39| `#!/usr/bin/env -S bash -e` | Shell |
40| `#!/usr/bin/env node` | Not coloured |
41| Anything not starting `#!` | Not coloured |
42
43The order is fixed — extension, then name, then first line — and the first to decide wins.
44
45Everything 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.
46
47## Classes
48
49Every scanner produces the same vocabulary of classes, and each maps to one theme key.
50
51| Class | Theme key | Produced by |
52| --- | --- | --- |
53| `identifier` | `syntax.identifier` | Golo, TOML, JavaScript, shell, YAML, Dockerfile |
54| `keyword` | `syntax.keyword` | Golo, JavaScript, shell, HTML (doctype), XML, Dockerfile |
55| `type` | `syntax.type` | Golo (capitalised names and module paths), TOML (table headers), YAML (tags) |
56| `builtin` | `syntax.builtin` | Golo (the interpreter's functions), JavaScript, shell (builtins and expansions), YAML (anchors and aliases), Dockerfile (variables) |
57| `constant` | `syntax.constant` | Golo, TOML, JavaScript, shell, YAML, HTML and XML (entities) |
58| `function` | `syntax.function` | Golo, JavaScript, shell (the command) |
59| `string` | `syntax.string` | all |
60| `char` | `syntax.char` | Golo (`'c'`) |
61| `number` | `syntax.number` | Golo, TOML, JavaScript, shell, YAML, Dockerfile |
62| `comment` | `syntax.comment` | Golo, TOML, JavaScript, shell, HTML, YAML, XML, Dockerfile |
63| `operator` | `syntax.operator` | Golo, TOML, JavaScript, shell, HTML, YAML (block scalar headers), XML, Dockerfile |
64| `punctuation` | `syntax.punctuation` | Golo, TOML, JavaScript, shell, Markdown, YAML, Dockerfile |
65| `heading` | `syntax.heading` | Markdown |
66| `tag` | `syntax.tag` | HTML, XML |
67| `attribute` | `syntax.attribute` | HTML, XML, Dockerfile (flags) |
68| `emphasis` | `syntax.emphasis` | Markdown |
69| `link` | `syntax.link` | Markdown |
70
71Golo produces no `heading`, `tag`, `attribute`, `emphasis` or `link` span. In `turbo-classic`, `syntax.number` and `syntax.constant` are both magenta and `syntax.char` is the green of `syntax.string`, so `42` and `true` share a colour there and so do `'x'` and `"x"`; other themes separate them. See [how to write your own theme](../how-to/write-a-theme.md) if you want to change it.
72
73## Golo
74
75Hand-written, in `internal/gololang`, against GoloScript's `lexer/lexer.go` and `token/token.go`. What the lexer reads as one token, the scanner colours as one span.
76
77**Four constructs cross a line break**, and are carried to the next line exactly as the lexer reads them: a `----` block comment to its closing `----`; a `"…"` string to its closing quote; a `"""…"""` multi-line string to its closing three quotes; a `'…'` character literal to its closing apostrophe. None of the four nests. So an unterminated string colours the rest of the file, until a quote — which is what the interpreter reads it as.
78
79| Recognised | As |
80| --- | --- |
81| `and`, `augment`, `augmentation`, `await`, `break`, `case`, `catch`, `continue`, `else`, `finally`, `for`, `foreach`, `function`, `if`, `import`, `in`, `is`, `isnt`, `let`, `local`, `match`, `module`, `not`, `oftype`, `or`, `orIfNull`, `otherwise`, `return`, `spawn`, `struct`, `then`, `throw`, `try`, `union`, `var`, `when`, `while`, `with` | keyword |
82| `true`, `false`, `null` | constant |
83| the interpreter's 157 builtins — `println`, `print`, `str`, `len`, `list`, `map`, `set`, `array`, `vector`, `range`, `readFile`, `toJSON`, `fromJSON`, `httpGet`, `DynamicObject`, … | builtin |
84| any other name starting with an ASCII capital — `Point`, `Shape`, `Circle`, `Result_Failure`, `Some` | type |
85| the dotted path after `module` or `import``hello.World`, `gololang.Errors`, `java.util.List` — as one span | type |
86| the name after `function``main` in `function main = \|args\|` | function |
87| any other lower-case name immediately before `(` | function |
88| any other name: any Unicode letter or mark, `_`, or an emoji, then letters, digits and the same — `x`, `été`, `名前`, `😀`, `🚀launch` | identifier |
89| `"…"` with `\n \t \r \\ \" \' \0 \xHH` escapes, across lines | string |
90| `"""…"""`, across lines, no escapes | string |
91| `'…'` with the same escapes, across lines | char |
92| `42`, `3.14`, `1.5e-3`, `2E10`, `42L`, `3.14F`, `2.0f` | number |
93| `#` to the end of the line, a shebang included | comment |
94| `----``----`, across lines | comment |
95| `..`, `...` | operator |
96| runs of `+-*/%=<>!&\|^~?:` — including `->`, `?:`, `==`, `!=`, `<=`, `>=` | operator |
97| `()[]{},;` and a lone `.` | punctuation |
98| `$` in `augment Shape$Circle` | punctuation |
99
100**A point joins a number only when a digit follows it.** That is the lexer's own test, and it is what keeps `1..3` a number and a range rather than the double `1.` and a stray `.3`.
101
102**An exponent may have no digits.** The lexer reads `1e` as a float and leaves the parser to complain, so `1e` is one number span.
103
104**A capitalised name is a type by convention, not by rule.** Golo lets you write `let Count = 1`, and it is coloured as a type all the same. Structs, unions, variants and augmentation targets are what people capitalise, and the colour follows the people.
105
106**`Some`, `None`, `Ok` and `Err` are types, not constants.** They are variants of ordinary unions declared in `gololang.Errors`, available after an `import`, not builtins.
107
108**`DynamicObject` is a builtin, capital and all.** It is in the interpreter's table, and the table wins over the case rule.
109
110**Names may hold any Unicode letter, and emoji.** The lexer's `isLetter` admits letters, marks, `_` and four emoji blocks (emoticons, miscellaneous symbols and pictographs, transport and map symbols, supplemental symbols and pictographs); the scanner uses the same rule.
111
112**Colouring follows the lexer, not the parser.** GoloScript's parser, as of v0.1.1, refuses several tokens its lexer reads: the `L`, `F` and `f` suffixes, a `'c'` character literal, the `..` range, `orIfNull`, `oftype` and `local function`. They are coloured as the lexer reads them, and the language server marks the line when the parser refuses it. `demos/syntax-tour/lexer-only.golo` holds one of each.
113
114**Not recognised**, each for a stated reason:
115
116| Not recognised | Because |
117| --- | --- |
118| `1_000` as one number | The lexer has no digit separator: `_` starts a name, so this is `1` and then `_000` |
119| `0xFF`, `0b1010`, `0o17` as numbers | The lexer has no base prefixes: `0xFF` is `0` and then the name `xFF` |
120| `.5` as a number | The lexer requires a digit before the point, so this is a dot and then `5` |
121| `42l` as a long | The lexer accepts only the upper-case `L`, so this is `42` and the name `l` |
122| `---` as a comment | Four dashes open a block comment; three are an operator run |
123| A keyword after `:` as a method name | `obj: match()` keeps `match` a keyword — the scanner does not track what a colon introduces |
124| An escape inside `"""…"""` | The lexer appends every rune until the three quotes, so `"""a\"""` ends at its first `"""` |
125| A constructor as anything but a type | Nothing in the syntax separates `Circle(1.0)` from a type applied to arguments |
126| An unterminated string stopping at its line | The interpreter reads to the closing quote wherever it is, so the colour follows it — the opposite of Turbo MoonBit's decision, for the opposite reason |
127| Whether a name is bound in this scope | Nothing here reads more than one line at a time; that is the language server's question, and [F1 answers it](../how-to/ask-about-code.md) |
128
129## TOML
130
131| Recognised | As |
132| --- | --- |
133| `# comment` | comment |
134| `[table]`, `[[array]]` | the name as a type, the brackets as punctuation |
135| `key =` | identifier, then operator |
136| `"basic"`, `'literal'`, `"""multi-line"""`, `'''multi-line'''` | string |
137| `true`, `false` | constant |
138| numbers, dates, times, `inf`, `nan` | number |
139
140## YAML
141
142A 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.
143
144| Recognised | As |
145| --- | --- |
146| `# comment` | comment |
147| `key:` before a space or the end of the line | the key as an identifier, the colon as punctuation |
148| `"quoted": 1`, `'quoted': 1` | the quoted key as an identifier |
149| `- ` opening a sequence entry | punctuation |
150| `"…"`, `'…'` | string |
151| `true`, `false`, `yes`, `no`, `on`, `off`, `null` | constant, whatever their case |
152| numbers, dates and times written without quotes | number |
153| `&anchor`, `*alias` | builtin |
154| `!!str`, `!Custom` | type |
155| `---`, `...` | the whole line as punctuation |
156| `{`, `}`, `[`, `]`, `,` | punctuation |
157| `\|`, `>`, with their chomping and indentation indicators | the header as an operator, the body as a string |
158
159**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.
160
161**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.
162
163**A `#` needs a space before it to start a comment**, so `colour: ff#00aa` is one scalar.
164
165| Not recognised | Because |
166| --- | --- |
167| 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 |
168| Multi-document streams as separate documents | `---` is coloured, but nothing is reset at it; nothing in the colouring depends on document boundaries |
169| 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 |
170
171## Markdown
172
173| Recognised | As |
174| --- | --- |
175| `# Heading``###### Heading` | the whole line as a heading |
176| `**bold**`, `__bold__`, `*italic*`, `_italic_` | emphasis |
177| `` `code` `` | string |
178| `[text](target)`, `![alt](src)` | the whole thing as a link |
179| `- `, `* `, `+ `, `1. `, `1) ` | the marker as punctuation |
180| `>` | punctuation |
181| `---`, `***`, `___` | punctuation |
182| ` ``` ` and `~~~` fences | the whole block, opening and closing lines included, as a string |
183
184A fenced block is **one colour whatever language it announces**: ```` ```golo ```` does not colour its contents as Golo. 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.
185
186The run of markers opening emphasis must be matched by a run of the same length, so `**bold**` is one span rather than two italics.
187
188## JavaScript
189
190| Recognised | As |
191| --- | --- |
192| `const`, `let`, `function`, `class`, `async`, `await`, `import`, `export`, … | keyword |
193| `true`, `false`, `null`, `undefined`, `NaN`, `Infinity`, `this` | constant |
194| `console`, `document`, `window`, `Array`, `Object`, `Promise`, `Math`, `JSON`, … | builtin |
195| a name immediately before `(` | function |
196| `"…"`, `'…'` | string |
197| `` `` ``, interpolations included, across lines | string |
198| `//` to end of line, `/* … */` across lines | comment |
199| `42`, `3.14`, `0x1f`, `0b1010`, `0o777`, `1_000_000`, `1e6`, `10n` | number |
200| runs of `+-*/%=<>!&|^~?:` | operator |
201| `()[]{},;.` | punctuation |
202
203**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.
204
205Globals are recognised by name, so a file that shadows `Math` still has it coloured as a builtin — the same rule Golo's builtins follow here.
206
207## HTML
208
209| Recognised | As |
210| --- | --- |
211| `<tag`, `</tag`, `>`, `/>` | tag |
212| attribute names, including `data-*`, `xlink:href`, `@click`, `v-bind.prop` | attribute |
213| `=` | operator |
214| `"…"`, `'…'` | string |
215| `<!-- … -->`, across lines | comment |
216| `&amp;`, `&#169;` | constant |
217| `<!DOCTYPE …>` and other declarations | keyword |
218
219Text between tags is not coloured. A bare `&` with no `;` within 32 characters is left alone, because it is legal text.
220
221**The contents of `<script>` and `<style>` are not coloured** as JavaScript and CSS.
222
223## XML
224
225Its 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.
226
227| Recognised | As |
228| --- | --- |
229| `<?xml version="1.0"?>` and other processing instructions | the target and `?>` as keyword, the pairs between as attributes and strings |
230| `<!DOCTYPE …>` and the other `<!` forms | keyword |
231| `<!-- … -->`, across lines | comment |
232| `<![CDATA[ … ]]>`, across lines | string |
233| `<tag`, `</tag`, `>`, `/>` | tag |
234| `<ns:tag>`, `xsi:type` | the prefix and the local name as **one** span |
235| attribute names | attribute |
236| `=` | operator |
237| `"…"`, `'…'` | string |
238| `&amp;`, `&#169;` | constant |
239
240**A comment and a CDATA section close on different delimiters**, and are carried separately: a `-->` inside a CDATA section does not end it.
241
242**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.
243
244Text between tags is not coloured.
245
246## Shell
247
248Applies to `sh`, `bash` and `zsh` alike: the keywords recognised are the ones they share.
249
250| Recognised | As |
251| --- | --- |
252| `if`, `then`, `fi`, `for`, `while`, `case`, `esac`, `function`, `return`, … | keyword |
253| `true`, `false` | constant |
254| `echo`, `printf`, `export`, `local`, `read`, `cd`, `set`, `source`, … | builtin |
255| `$NAME`, `${…}`, `$(…)`, `$1`, `$?`, `$@` | builtin |
256| the **first bare word on a line** | function |
257| every later bare word, and `NAME` in `NAME=value` | identifier |
258| `'…'`, with nothing escaped or expanded inside | string |
259| `"…"`, with the expansions inside it coloured as expansions | string |
260| `#` to end of line | comment |
261
262`$(a $(b) c)` is one span: nesting is counted. An option such as `-euo` is one word, not a minus and a word.
263
264**Heredocs are not recognised.** `<<EOF` and the text after it are coloured as ordinary shell.
265
266## Dockerfile
267
268| Recognised | As |
269| --- | --- |
270| `FROM`, `RUN`, `COPY`, `ADD`, `ARG`, `ENV`, `CMD`, `ENTRYPOINT`, `EXPOSE`, `LABEL`, `USER`, `VOLUME`, `WORKDIR`, `HEALTHCHECK`, `ONBUILD`, `SHELL`, `STOPSIGNAL`, `MAINTAINER` | keyword, in any case |
271| `AS`, `NONE` | keyword |
272| `# comment`, including the `# syntax=` and `# escape=` directives | comment |
273| `--from=builder`, `--chown=me:me` | the flag name as an attribute |
274| `$NAME`, `${NAME}`, `${NAME:-default}` | builtin, as one span to the closing brace |
275| `"…"`, `'…'` | string |
276| a trailing `\` | operator |
277| numbers | number |
278| paths and image references — `/usr/local/bin`, `golang:1.26-alpine` | identifier, as **one** span |
279
280**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.
281
282**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.
283
284| Not recognised | Because |
285| --- | --- |
286| 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 |
287| Heredocs in a `RUN` | The same reason the shell scanner does not recognise them |
288| Which stage a `--from` names | Nothing here reads the rest of the file |
289
290## See also
291
292- [Theme file format](themes.md) — every key these classes resolve to
293- [Colouring and completion](../explanation/colouring-and-completion.md) — why the scanners are written this way
294- [How to write your own theme](../how-to/write-a-theme.md)