turbo-editors/turbo-rustpublic Fork 0
v1.0.1
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.

summary.md · 101 lines · 13.8 KBmarkdown Blame HistoryRaw
📦 Turbo Rust 713ea5c k33g 12h ago1# turbo-rust — project summary
2
3*A snapshot of the present. No history here — that is `history.md`.*
4
5## What this is
6
7A Turbo C-style editor for Rust, written in Go: a full-screen terminal IDE with a menu bar, movable overlapping windows, modal dialogs, mouse support, Rust syntax colouring, loadable TOML themes, completion from `rust-analyzer`, terminal windows running a real shell, per-project settings, a project tree, snippets, and the cargo toolchain a menu away.
8
9It is a thin editor on top of [turbo-core](https://rickub.com/turbo-editors/turbo-core), the library every Turbo editor shares. What is in this repository is `main.go` and `internal/rustlang` — about seven hundred lines, six hundred of which are the scanner.
10
11Module path `rickub.com/turbo-editors/turbo-rust`. Go 1.26.5. Remote: `ssh://git@rickub.com/turbo-editors/turbo-rust.git`.
12
13Created 2026-09-01, the same day turbo-core was extracted, and the reason it was extracted.
14
15## Architecture
16
17Two packages here; everything else is the library.
18
19```
20main → {turbo-core/app, turbo-core/profile, turbo-core/settings, turbo-core/theme,
21 turbo-core/version, internal/rustlang, tcell}
22internal/rustlang → {turbo-core/profile, turbo-core/syntax}
23```
24
25| File | What it holds |
26| --- | --- |
27| `main.go` | Flags, the terminal, and the wiring: register Rust, build the profile, read the project's settings, hand them to `app.New`, start rust-analyzer in the crate root, run the loop |
28| `internal/rustlang/rustlang.go` | The profile: name, slug, `Rus~t~` menu, `Cargo.toml` root marker, rust-analyzer with the two directories it is looked for in |
29| `internal/rustlang/scan.go` | The scanner's dispatcher, comments and attributes |
30| `internal/rustlang/literals.go` | Strings, raw strings, byte literals, characters, lifetimes |
31| `internal/rustlang/words.go` | Numbers, keywords, types, macros |
32| `internal/rustlang/templates.go` | The three starter files a project gets |
33
34`docs/diagrams/packages.drawio` is generated from `go list` and verified against it edge for edge.
35
36## Decisions in force
37
38- **The toolchain menu is `Rus~t~`, on Alt-T, not `~C~argo`.** `R` is Run's and `S` is Search's, so the hot key lands on the last letter of the word, which reads as an afterthought — and `C` was free. Naming it Cargo was still rejected: the menu holds whatever the project put in its tools file, and the first tools file anybody writes outgrows the language's own toolchain. A menu called Cargo holding `docker compose up` is a lie about what the menu is.
39- **Rust is scanned by hand, in six hundred lines.** Go has a lexer in its standard library and Turbo Go uses it; `rustc` is not a Go library and rust-analyzer's parser is a Rust crate, so the choice was a hand-written scanner or shelling out on every keystroke. The scanner is written against turbo-core's `LineScanner`, in the same style as the five the library ships.
40- **Three constructs cross a line break and are carried exactly.** A block comment carries a **depth**, not a flag, because Rust nests them and a flag ends `/* a /* b */ c */` at the first `*/`. A raw string carries its **hash count**, because it ends at a quote followed by exactly that many. An ordinary string can carry too, because Rust allows a real newline inside `"…"`.
41- **An attribute is not carried.** `#[…]` that runs past its line is coloured to the end and dropped, because an unclosed one is nearly always half-typed, and carrying it would paint the rest of the file.
42- **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'` a character, `'static` a lifetime, `'\u{1F600}'` a character. Getting it wrong strings the rest of the line, so it has tests of its own. A lifetime is coloured as a **type**, because it is a generic parameter declared and used where one is.
43- **A leading capital means a type**, leaning on Rust's naming convention: type, trait and enum variant are all `UpperCamelCase` and nothing else is. It is visibly a heuristic in one place — a `SCREAMING_SNAKE_CASE` constant is coloured as a type — and the reference says so rather than leaving somebody to find out. A second rule for it was rejected: it would mis-colour a type whose name is an acronym, and trading one wrong answer for another is not progress.
44- **A macro takes its `!`**, and `a != b` is told from it by the `=`. **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. **`::` and `:` are punctuation** and **`..`/`..=` are operators**, both against the rune classes turbo-core's helpers would otherwise give them.
45- **`None`, `Some`, `Ok` and `Err` are coloured as constants** although they are Option's and Result's rather than the language's. A reader meets them before any other variant and reads them as they read `true`.
46- **The Code menu is turbo-core's, and so are its eight questions.** Describe symbol and Go to definition moved into it from Run and Search; their keys did not change. This repository documents the menu and owns none of it — as with everything else the two editors share, a change to it is a `/methodical-dev` cycle in turbo-core.
47- **The settings file a project creates turns autosave on.** A project that has gone to the trouble of having one has said what it wants, and the file is the visible, editable place to say otherwise. `settings.Default()` — what applies with no settings file at all — stays **off**: the editor must not write to disk in a directory somebody merely started it in. Two different statements, set in two different places on purpose.
48- **A workspace, not a `replace`, is how to build against an unreleased turbo-core.** `go work init . ../turbo-core` changes no tracked file, so there is nothing to forget before committing; `go.work` is gitignored in all three repositories. The commented-out `replace` at the bottom of `go.mod` still works and is documented as the older way, with its hazard named.
49- **The build runs the binary it just built and checks it names the right version.** `scripts/check-version.sh` is called by `make build`, by `scripts/install.sh` before the install, and by `03-build-releases.sh`. A linker stamp is a string and a wrong one is not an error — `-X` naming a symbol that does not exist links happily and stamps nothing — so nothing but running the binary catches it. The comparison is an **equality**: `0.2.0` is a substring of `10.2.0`.
50- **rust-analyzer is looked for in `CARGO_HOME/bin` and `RUSTUP_HOME/bin` after PATH**, and the installer *runs* it rather than stat-ing it. rustup installs a shim called `rust-analyzer` whether or not the component is there, and the shim fails only when run — so "the file is there" is not the question worth asking.
51- **Snippets indent with four spaces, not tabs**, because that is what rustfmt does; a tab in a Rust snippet lands in somebody's file and disappears on the next `cargo fmt`. There is a test for it, and another that no template still says `turbo-go`.
52- **The tests drive the real editor.** `internal/rustlang/editor_test.go` builds a whole Turbo Rust on a simulated terminal through turbo-core's public API. The library's suite proves the library works; these prove *this editor is assembled correctly* — that Register was called, that the profile reached the menu bar, that a `.rs` file comes out coloured and a `.go` file does not.
53
54Everything else about the editor's behaviour — the event loop, the menus, the dialogs, the terminal emulator, the theme rules — is turbo-core's, and its `.memory/summary.md` is where those decisions are recorded.
55
56- **A tool's command can ask for values.** A `{{label}}` in it opens a box before the command runs; the value is shell-quoted unless the label ends in `...`. The feature is turbo-core's — see its summary — and what belongs to this editor is the starter file's comments, which teach the syntax without adding a sixth tool.
57- **Agent windows are turbo-core's, and what belongs here is the starter file.** `acp.toml.tmpl` is the fourth embedded template, and `profile.Templates.Agents` is the whole of Turbo Rust's contribution to the feature. The example agent is `docker agent serve acp .turbo-rust/agent.yaml`; the only other thing about this editor in it is the sentence saying a ```rust fence is coloured by the scanner this editor colours its own files with. Every other editor got agent windows the same way — one file, one line. The reasoning, and why it could not have been built here, is in `docs/*/explanation/agent-windows.md`.
58- **The starter agents file teaches the window's keyboard as well as the format.** `Enter`, `Alt-Enter`, `Tab`, `Esc`, `Ctrl-W` and the copying keys are all in its comments, because a file the editor hands you is the one document a user is guaranteed to see.
59
60## Build, test, run
61
62```bash
63make install # build + install onto PATH (scripts/install.sh)
64make build # → bin/turbo-rust
65make test # the whole suite; the single documented command
66make check # fmt + vet + test — what a commit should pass
67make run FILE=src/main.rs
68go test -short ./... # skips the test that starts a real rust-analyzer
69```
70
71Quality gate, separate from the tests:
72
73```bash
74python3 ~/.claude/skills/quality/scripts/quality_report.py --workspace .
75```
76
77## State as of 2026-09-01
78
79- **Complete and green.** Whole suite passing; quality gate PASS at 0 errors, 0 warnings, 0 smells, complexity 98.
80- **Verified against a real rust-analyzer**: the editor writes a crate, opens a file, starts the server, types text that exists only in the buffer, and gets `String::len` back. Text already on disk would prove nothing.
81- **Verified in a real pty**: the menu bar reads `File Edit Search Run Options Window Snippets Rust Help`; a nested block comment, a raw string with quotes inside it, `println!` with its `!`, and `3u8` with its suffix each come out as one correctly-coloured run on the wire.
82- **`docs/` is 33 pages × EN + FR.** `reference/languages.md` documents the scanner's boundaries, and `internal/rustlang/reference_test.go` holds the code to every row of its Rust table.
83- **Released as v0.1.0** at `2d5dbec`, which is exactly HEAD — its first release ever, with a release page on Codeberg.
84- **Depends on `turbo-core v0.2.0`**, with no active `replace`. On `main` that is v0.1.0 and builds from the module proxy. On `feature/more-syntaxes` the `require` names **v0.2.0, which is not published yet**: that branch does not build until turbo-core is tagged and released, and `go.sum` has no entry for it. The old replace block is still there, commented out, as the documented way to develop across the three repositories.
85
86## Not yet established
87
88- **Agent windows have never been opened in this editor.** The feature is turbo-core's and was driven end to end from turbo-go against a real `docker agent` and a real llama.cpp; what is here is the starter file, covered by tests that create it, load it back and check it names this editor's own language. Nobody has run `turbo-rust`, pressed `Alt-A` and talked to an agent from it.
89
90
91- **Never used by a person for a working session.** Everything is verified by tests and by scripted pty runs; nobody has spent an hour editing Rust in it.
92- **No release has been cut.** The numbered scripts `01``04` came from turbo-go and are adapted, but `02` and `04` have never been run here — they publish, and publishing is not this session's to do.
93- **The scanner has met one file of Rust in anger.** It is covered by 30-odd tests and a broad sweep, but it has not been pointed at a large real crate.
94- **Windows and macOS are untested**, inherited from turbo-core.
95- **`macro_rules!` bodies are coloured as ordinary Rust**, which is usually right and sometimes not. Documented, not fixed.
96
97## State as of 2026-09-19 — moved to Rickub, released by a workflow
98
99- **Module path `rickub.com/turbo-editors/turbo-rust`**, depending on `rickub.com/turbo-editors/turbo-core v1.0.0` — the first turbo-core version published under that path (`v0.9.0` on the proxy still declares the Codeberg path and cannot be required as `rickub.com/…`). Every import, the Makefile's `VERSION_PKG`, `scripts/install.sh`, the README and the docs say `rickub.com`. `GOWORK=off make check` green. The repository on this side is a fresh `git init` with `origin` at `ssh://git@rickub.com/turbo-editors/turbo-rust.git` and **no commit yet**; `01-release.tag.sh` makes the first one.
100- **Releases are one script and one workflow**, modelled on turbo-core's and identical to turbo-go's. `01-release.tag.sh` runs `make check` under `TURBO_RUST_RELEASING=1`, refuses a tag taken locally or on origin (bump, never move), refuses a `replace` in `go.mod`, commits, pushes the current branch, then tags and pushes the tag. That push starts `.github/workflows/release.yml`: `go test` with `TURBO_RUST_RELEASING=1`, `./02-build-releases.sh "${GITHUB_REF_NAME}"`, release notes from the tag message, a run artifact, then `softprops/action-gh-release@v2` attaching `turbo-rust-*`, `SHA256SUMS` and `README.md` with the job's own `GITHUB_TOKEN` — the only credential Rickub's release API accepts. **`02-release.publish.sh` and `04-release.upload-binaries.sh` are gone**; the build script is now `02-build-releases.sh`, takes the tag as `$1` (CI has no `release.env`), validates it, refuses a `replace`, and starts from an empty `release/${TAG}/`. `release.env` holds only `TAG` and `ABOUT`; `turbo-rust.token.env` is read by nothing.
101- **`release_test.go`** runs `01` for real against a throwaway bare remote (publishes, then refuses the same tag), runs `02` alone to see it refuse `v0.o.0`, and asserts the workflow's trigger, `contents: write`, `./02-build-releases.sh`, `fail_on_unmatched_files`, docs linked at the tag, no `secrets.`, and `TURBO_RUST_RELEASING`. The copy of the module for the clone leaves out `.git`, `bin`, `release`, `kits`, `demo`, `demos`, `*.env` and `go.work*`; children run with `GOWORK=off`.