| 📦 Turbo Golo d710c1b k33g 12h ago | 1 | # turbo-golo — summary |
| 2 | |
| 3 | A snapshot of the present. Edited in place; the history is in `history.md`. |
| 4 | |
| 5 | ## What this is |
| 6 | |
| 7 | A Turbo C-style terminal IDE for **Golo**, written in Go, built on **[turbo-core](https://rickub.com/turbo-editors/turbo-core)** — the library Turbo Go, Turbo Rust, Turbo Python and Turbo MoonBit already share. This repository holds the command, the profile that says the editor is for Golo, and the Golo scanner. Everything else — the event loop, the windows, the dialogs, the themes, the LSP client, the terminal emulator, the project tree, the snippets and tools machinery — is the library's, and none of it is copied here. |
| 8 | |
| 9 | **Golo is the language; GoloScript is the implementation.** Golo was created for the JVM (Eclipse Golo); GoloScript is the independent reimplementation in Go — `https://codeberg.org/TypeUnsafe/golo-script` — whose `golo` binary this editor talks to. The docs say "Golo" for the language and its files, "GoloScript" for the implementation and its toolchain, and `golo` for the binary. Never "GoloScript file". |
| 10 | |
| 11 | Module `rickub.com/turbo-editors/turbo-golo`, `require`ing turbo-core **v0.5.0** from the module proxy with **no active `replace`**. The commented-out `replace` at the bottom of `go.mod` documents the escape hatch without being one; `01-release.tag.sh` refuses to tag a release whose `go.mod` carries a live one. |
| 12 | |
| 13 | ## Layout |
| 14 | |
| 15 | | | | |
| 16 | | --- | --- | |
| 17 | | `main.go` | flags (`-theme`, `-list-themes`, `-no-lsp`, `-version`), the terminal, `gololang.Register()`, the profile, the loop | |
| 18 | | `internal/gololang/gololang.go` | `Name`, `Slug`, `Language`, `Profile()`, `Register()`, `ServerArgs()`, `ServerDirs()` | |
| 19 | | `internal/gololang/scan.go` | the dispatcher, `#` and `----` comments, the carry | |
| 20 | | `internal/gololang/literals.go` | `"…"`, `"""…"""`, `'c'` | |
| 21 | | `internal/gololang/words.go` | numbers, keywords, constants, builtins, the capital-letter rule, the name after `function`, the path after `module`/`import` | |
| 22 | | `internal/gololang/*.toml.tmpl` | the three starter files, embedded by `templates.go` | |
| 23 | | `diagram_test.go` | holds `docs/diagrams/packages.drawio` to `go list` | |
| 24 | | `internal/gololang/reference_test.go` | holds `docs/*/reference/languages.md` to the scanner | |
| 25 | | `internal/gololang/editor_test.go` | the editor assembled on a `SimulationScreen`, and the real `golo lsp` driven end to end | |
| 26 | | `docs/{en,fr}/` | 34 pages each (README included), Diátaxis | |
| 27 | | `demos/` | three Golo programs: `hello`, `shapes` (with `shapes_test.golo`), `syntax-tour` (`tour.golo` runs; `lexer-only.golo` is coloured but does not) | |
| 28 | |
| 29 | ## How to build, test and measure |
| 30 | |
| 31 | ```bash |
| 32 | make check # fmt, vet, then the whole suite — what a commit should pass |
| 33 | make build # into bin/turbo-golo, then scripts/check-version.sh on the binary |
| 34 | make install # build, install onto PATH, report what it found (runs golo lsp to check the server) |
| 35 | go test ./... # the golo-lsp tests skip themselves without golo on PATH, and under -short |
| 36 | ``` |
| 37 | |
| 38 | Quality gate, separate from the tests: |
| 39 | |
| 40 | ```bash |
| 41 | python3 ~/.claude/skills/quality/scripts/quality_report.py --workspace . |
| 42 | ``` |
| 43 | |
| 44 | To build against a turbo-core you have changed but not released: |
| 45 | |
| 46 | ```bash |
| 47 | go work init . ../turbo-core |
| 48 | go list -f '{{.Dir}}' rickub.com/turbo-editors/turbo-core/app # must NOT be under pkg/mod |
| 49 | ``` |
| 50 | |
| 51 | `go.work` and `go.work.sum` are gitignored. **Everything still builds and still passes** while testing the published library instead of your changes, so run that second line. |
| 52 | |
| 53 | ## Decisions in force |
| 54 | |
| 55 | - **No root marker.** `RootMarkers` is `nil`, the only editor in the family where it is. Golo has no manifest — a script is a file, a program is a directory of them — so `app.ProjectRoot` answers with the directory of the file being edited, which is also all `golo lsp` needs: it resolves imports from the modules embedded in the binary, never from disk. A marker would make a walk look like part of a rule that does not exist. |
| 56 | - **The language server is the interpreter**: `golo lsp`, over stdio. Nothing separate to install. The `lsp` argument is load-bearing — `golo` with no argument starts its REPL and reads stdin as Golo, which the editor would see as a server that answers nothing and never dies. Searched on `PATH`, then `/usr/local/bin` (where GoloScript's `install.sh` writes); there is no per-user toolchain directory and no environment variable naming one, so nothing else is listed. |
| 57 | - **`golo lsp` answers eight of turbo-core's nine questions since GoloScript v0.2.0** — completion, hover, definition, documentSymbol, references, implementation, workspace/symbol — and publishes diagnostics unasked. It does not advertise typeDefinition (`unsupported method`). References and implementations are within the file, and an implementation is the declaration itself (Golo has no interfaces); workspace/symbol searches every `.golo` under the root, open or not, module names included, and an empty query lists everything. Until v0.2.0 only the first four were advertised, and `TestGoloLSPAnswersNoneOfTheFourQuestionsItDoesNotAdvertise` went red on 2026-09-19 exactly as designed; it is now three positive tests plus `TestGoloLSPDoesNotAnswerTypeDefinitionWithRealGoloLSP`. Its diagnostics include two lints beyond syntax errors: `:`/`.` confusion, and C-style `//` and `/* */` comments — the tutorial's Step 8 uses the second. |
| 58 | - **The toolchain menu is `~G~olo`, `Alt-G`.** G is free (fixed menus take F, E, S, R, C, O, W, N, H). Named after the language, not after `golo`, `gogolo` or `wagolo`. |
| 59 | - **`Language` is `"Golo"`**, what the About box and status bar read out. The registry name is `golo`, lower case like every other entry. |
| 60 | - **Strings are carried across lines to the closing quote**, the opposite of Turbo MoonBit's decision, for the opposite reason: GoloScript's lexer reads them that way, so an unterminated string colours the rest of the file until a quote turns up, and that colour is a true statement about what the interpreter will read. Character literals `'c'` are carried the same way; `"""…"""` has no escapes inside. `----` block comments cross lines without nesting; three dashes are an operator run. |
| 61 | - **Numbers follow the lexer, not intuition.** `.digits` only when a digit follows the point, so `1..3` is a number and a range; `e`/`E` exponent; suffixes `L`, `F`, `f`. **No** hexadecimal, binary, octal or `_` separators — `0xFF` is `0` then the name `xFF` — because the lexer has none. |
| 62 | - **A capitalised name is a type** (struct, union, variant, augmentation target). **`Some`, `None`, `Ok` and `Err` are types, not constants** — in Golo they are variants of ordinary unions from `gololang.Errors`, available only after an import, and colouring them as built in would say otherwise. The name after `function` is a function by position; the dotted path after `module` or `import` is one type span. |
| 63 | - **Names use the lexer's own predicate**, not turbo-core's ASCII one: any Unicode letter or mark, `_`, and four emoji blocks. `let 😀 = 1` and `function 🚀launch = …` are coloured, and so are `été` and `名前`. |
| 64 | - **The builtins table is held to the real `golo lsp`** by a test — the 157 names `evaluator.BuiltinNames()` lists minus the five `__`-prefixed test counters — rather than remembered. 38 keywords, 3 constants. |
| 65 | - **The scanner colours what the lexer reads, and the parser (v0.1.1) refuses some of it**: `42L`, `3.14F`, `'c'`, `..`, `orIfNull`, `oftype`, `local function`. A coloured token is not a promise the interpreter accepts it; `reference/languages.md` says so and `demos/syntax-tour/lexer-only.golo` holds them. |
| 66 | - **There is no `golo fmt` and no `golo lint`.** The lints live in the language server, so the starter tools file has no Format or Lint entry — Run comes first, because for a scripting language "what does it print?" is the question asked most often. |
| 67 | - **Eight tools in the Golo menu plus `Echo` in a `Tools` menu**: Run, Test, Test one, Debug, REPL, New script, Build native (`gogolo`), Build wasm (`wagolo`). **Six use a `{{placeholder}}`**, more than any sibling, because with no manifest every command that touches a file has to be told which one. All commands were run against the real binaries. |
| 68 | - **Snippet bodies are TOML literal strings, indented two spaces.** Golo strings carry `\n` and `\"`, which TOML basic strings would resolve; two spaces is the convention in every GoloScript example, and Golo has no formatter to disagree with. |
| 69 | - **`autosave = true` in the starter settings file, `false` in `settings.Default()`.** Two statements in two places on purpose. |
| 70 | - **The starter templates are embedded files, not Go constants**, with the `.tmpl` suffix because `settings.toml.tmpl` holds `theme = %q`, which is not valid TOML. |
| 71 | - **A shebang naming `golo` is claimed** (`#!/usr/bin/env golo`): `#` opens a comment in Golo, so the interpreter reads the line as one. |
| 72 | - **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 Golo's contribution to the feature. The example agent is `docker agent serve acp .turbo-golo/agent.yaml`; the only other thing about this editor in it is the sentence saying a ```golo 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`. |
| 73 | - **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. |
| 74 | |
| 75 | ## State as of 2026-09-14 |
| 76 | |
| 77 | - **Complete and green, uncommitted.** `go build`, `go vet`, `gofmt -l` clean; **250 tests pass, 0 skipped** with `golo` v0.1.1 installed. The repository is at its initial commit `7069d2c` with everything untracked. |
| 78 | - **Quality gate: PASS**, run #2 (run #1 failed on 2 smells, fixed the same minute). 0 errors, 0 warnings, 0 smells; total complexity 54, worst file `words.go` at 29 against a limit of 60; 1002 lines, 491 of code. |
| 79 | - **Documentation**: 34 pages × EN + FR, a `README.md` at the root, `demos/README.md`, and `docs/diagrams/packages.drawio` checked against `go list`. The French tutorial was the last page written, on the second session of the day. |
| 80 | - **Verified in a real pty** (`/tmp/tg/tut.raw`, replayed with `/tmp/tg/screen.py`): the bar ` File Edit Search Run Code Options Window Snippets Golo Help`; the `Tools` menu appearing between Golo and Help once the tools file exists; `Run` asking `script, e.g. main.golo:` then a terminal window printing the three greetings; **a `// run it` line showing `×` (`91;44;1`) in the gutter and `⚠ GoloScript has no '//' line comments…` on the status bar**; the Options menu. Tutorial colours read back as SGR: keyword `97;44;1`, type `96;44`, function `93;44;1`, builtin `96;44;1`, identifier `93;44`, string `92;44`, comment `38;2;143;143;143`, operator `37;44`; numbers `95;44`. From File, `→` five times reaches Options and eight reaches Golo — read off the wire. |
| 81 | - **Registered in the family.** turbo-core's `README.md`, both doc READMEs, both workspace how-tos, `profile/profile.go`'s comment and `.memory/summary.md` count five editors; turbo-python's and turbo-moonbit's architecture pages say "all five editors". turbo-core's `.go` strings were swept for hardcoded language names against v0.5.0: every hit innocent, **no library change needed** — Turbo Golo is the first editor with no root marker and the library's fallback handled it unchanged. |
| 82 | |
| 83 | ## Known boundaries |
| 84 | |
| 85 | - **Definition and document symbols are file-local**: top-level functions and unions, variants nested under their union. Imports of *user* modules on disk are not resolved by the server. |
| 86 | - **A diagnostic without a line number lands on line 1**, and the whole line is marked — the server gives no column. |
| 87 | - **`typeDefinition` reports nothing found**, because the server does not provide it; `references`, `implementation` and `workspace/symbol` are answered since GoloScript v0.2.0. |
| 88 | |
| 89 | ## Not yet established |
| 90 | |
| 91 | - **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-golo`, pressed `Alt-A` and talked to an agent from it. |
| 92 | |
| 93 | |
| 94 | - **No record that the tests were falsified by mutation.** The session that wrote them ended before writing this file, and left only `/tmp/tg/FACTS.md` behind. Every sibling's first session ran a mutation pass; whether this one did is unknown. Running one is the next thing worth doing before a release. |
| 95 | - **Never run on macOS or Windows.** Everything here was verified on Linux/arm64. A binary built in this sandbox is an ELF. |
| 96 | - **No CI.** There is no pipeline configuration in the repository. |
| 97 | - **Never released.** No tag exists; `release.env` says `TAG="v0.1.0"`, which is right for a first tag. `01`–`04` have only ever been read here, never run. |
| 98 | - **Performance on a large file is unmeasured**, and a string carried across many lines re-scans on every edit like any carry does. |
| 99 | - **Nothing checks the demos automatically.** They were run by hand under `golo` v0.1.1; a future GoloScript could change what the parser accepts without anything here noticing. |
| 100 | - **The `golo lsp` tests have only been run against v0.1.1.** The builtins table is held to that version's `BuiltinNames()`; a newer golo that adds a builtin will fail the test, which is the intent. |
| 101 | |
| 102 | ## State as of 2026-09-19 — moved to Rickub, released by a workflow |
| 103 | |
| 104 | - **Module path `rickub.com/turbo-editors/turbo-golo`**, 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-golo.git` and **no commit yet**; `01-release.tag.sh` makes the first one. |
| 105 | - **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_GOLO_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_GOLO_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-golo-*`, `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-golo.token.env` is read by nothing. |
| 106 | - **`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_GOLO_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`. |