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.

🛟 Updated. 28d5985 · on v1.0.0 · k33g · 14h ago
what-belongs-here.md · 61 lines · 4.7 KBmarkdown
Blame HistoryOpen raw

What belongs here — explanation

What is this about?

turbo-core and the editors built on it are one codebase split in two. This page is about where the split falls, why it falls there, and what to do when something new does not obviously belong on either side.

The test

Ask: would a third editor, for a language nobody has thought of yet, want this exactly as it is?

If yes, it is the library's. If it would want something like it but not this, it belongs to the editor — and what the library owes it is a seam, not a special case.

That question is what puts the Go scanner in Turbo Go and the Markdown scanner in the library. A Zig editor wants the Markdown scanner unchanged, because its README is Markdown. It does not want the Go scanner at all.

What is on each side

The library An editor
The editing widget, the windows, the menus, the dialogs Which language server, and how to find it
Eleven themes and the loader The name on the About box
TOML, YAML, Markdown, JavaScript, HTML, XML, Dockerfiles and shell colouring The colouring of its language
Reading and writing settings, snippets and tools files What is in those files when they are created
The LSP client and the process The label on the toolchain menu
The VT emulator and the pty The file that marks a project's root

Notice the pattern down the right-hand column: it is all statements about one language, and none of it is behaviour. That is not a coincidence — it is what made the extraction possible at all. An editor built on turbo-core contains almost no logic, which is why writing one is an afternoon rather than a fork.

The one place behaviour crosses the line

The scanner. A language's colouring is real code — Turbo Rust's is three files and three hundred lines — and it cannot be data, because a scanner for a language with nested block comments and raw strings is not expressible in a table.

That is why the library exports a scanner toolkit rather than a pattern language. Adding a language means writing ordinary Go beside the ones that already exist, rather than learning a notation. The cost is a wide public API; the alternative was a grammar format, which is a feature in its own right and which nobody would have been able to extend without learning it.

Things that are deliberately absent

A plugin system. An editor is a Go program that imports a library. There is no dynamic loading, no manifest and no ABI, and adding one would mean freezing the API of every package rather than of the handful a profile touches.

A configuration file for the profile. The profile could have been TOML read at start-up, which would make a new editor a file rather than a program. It would also make the scanner impossible to express, and a half-configurable editor — everything but the colouring — is worse than either whole answer.

A user-level tools file. Snippets are your habits and follow you between projects, so there is a user-level snippets file. A project's tools belong to its own toolchain, and a global one would offer go build in a Rust repository.

Language detection by content. A file is recognised by extension, then by shebang, and by nothing else. Guessing from the body of a file is wrong often enough to be worse than being quiet.

What to do when something does not fit

Two failure modes, both of which have happened here:

Putting an editor's opinion in the library. tools.DefaultMenu used to be the constant "Go". It was correct for a year and wrong the moment there were two editors. The fix was not to add a second constant; it was to notice that the default menu is a statement about an editor and move it into the profile.

Putting library behaviour in an editor. Turbo Go's main.go used to walk up looking for a go.mod. That walk is not about Go — every language has a project root — so it became app.ProjectRoot(p, files) with the marker in the profile, and Turbo Rust got it for free by writing "Cargo.toml".

The signal in both cases is the same: a piece of code that mentions one language by name and is not about that language.

How it relates to the rest

The boundary is enforced by the tests as much as by taste. turbo-core's own suite drives a fictional editor called Turbo Test — with its own slug, its own menu, its own templates — precisely so that a test cannot quietly assume Turbo Go's answers. A test in the library that expected the Go menu would be testing an editor's choices from inside the library those choices are made outside of.

See also

 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
# What belongs here — explanation

## What is this about?

turbo-core and the editors built on it are one codebase split in two. This page is about where the split falls, why it falls there, and what to do when something new does not obviously belong on either side.

## The test

Ask: **would a third editor, for a language nobody has thought of yet, want this exactly as it is?**

If yes, it is the library's. If it would want *something like* it but not this, it belongs to the editor — and what the library owes it is a seam, not a special case.

That question is what puts the Go scanner in Turbo Go and the Markdown scanner in the library. A Zig editor wants the Markdown scanner unchanged, because its README is Markdown. It does not want the Go scanner at all.

## What is on each side

| The library | An editor |
| --- | --- |
| The editing widget, the windows, the menus, the dialogs | Which language server, and how to find it |
| Eleven themes and the loader | The name on the About box |
| TOML, YAML, Markdown, JavaScript, HTML, XML, Dockerfiles and shell colouring | The colouring of *its* language |
| Reading and writing settings, snippets and tools files | What is *in* those files when they are created |
| The LSP client and the process | The label on the toolchain menu |
| The VT emulator and the pty | The file that marks a project's root |

Notice the pattern down the right-hand column: it is all *statements about one language*, and none of it is behaviour. That is not a coincidence — it is what made the extraction possible at all. An editor built on turbo-core contains almost no logic, which is why writing one is an afternoon rather than a fork.

## The one place behaviour crosses the line

The scanner. A language's colouring is real code — Turbo Rust's is three files and three hundred lines — and it cannot be data, because a scanner for a language with nested block comments and raw strings is not expressible in a table.

That is why the library exports a scanner toolkit rather than a pattern language. Adding a language means writing ordinary Go beside the ones that already exist, rather than learning a notation. The cost is a wide public API; the alternative was a grammar format, which is a feature in its own right and which nobody would have been able to extend without learning it.

## Things that are deliberately absent

**A plugin system.** An editor is a Go program that imports a library. There is no dynamic loading, no manifest and no ABI, and adding one would mean freezing the API of every package rather than of the handful a profile touches.

**A configuration file for the profile.** The profile could have been TOML read at start-up, which would make a new editor a file rather than a program. It would also make the scanner impossible to express, and a half-configurable editor — everything but the colouring — is worse than either whole answer.

**A user-level tools file.** Snippets are your habits and follow you between projects, so there is a user-level snippets file. A project's tools belong to its own toolchain, and a global one would offer `go build` in a Rust repository.

**Language detection by content.** A file is recognised by extension, then by shebang, and by nothing else. Guessing from the body of a file is wrong often enough to be worse than being quiet.

## What to do when something does not fit

Two failure modes, both of which have happened here:

**Putting an editor's opinion in the library.** `tools.DefaultMenu` used to be the constant `"Go"`. It was correct for a year and wrong the moment there were two editors. The fix was not to add a second constant; it was to notice that the default menu is a *statement about an editor* and move it into the profile.

**Putting library behaviour in an editor.** Turbo Go's `main.go` used to walk up looking for a `go.mod`. That walk is not about Go — every language has a project root — so it became `app.ProjectRoot(p, files)` with the marker in the profile, and Turbo Rust got it for free by writing `"Cargo.toml"`.

The signal in both cases is the same: a piece of code that mentions one language by name and is not about that language.

## How it relates to the rest

The boundary is enforced by the tests as much as by taste. turbo-core's own suite drives a fictional editor called Turbo Test — with its own slug, its own menu, its own templates — precisely so that a test cannot quietly assume Turbo Go's answers. A test in the library that expected the Go menu would be testing an editor's choices from inside the library those choices are made outside of.

## See also

- The shape that results: [architecture](architecture.md)
- How to put a language on the right side: [add a language](../how-to/add-a-language.md)