# Architecture — explanation ## What is this about? Turbo Go is a command, a profile and a scanner. Everything else — the editing widget, the windows, the menus, the dialogs, the themes, the terminal emulator, the file tree, the LSP client — is [turbo-core](https://rickub.com/turbo-editors/turbo-core), the library every Turbo editor is built on. That was not always true. Turbo Go was a single program of about eleven and a half thousand lines in fourteen packages until a second editor was wanted, at which point the fourteen moved into a library and one stayed here. This page is about the split that resulted. ## What is in this repository ``` main.go flags, the terminal, and the wiring internal/golang the whole of what makes this Turbo Go golang.go the profile: name, menu, server, root marker scan.go the Go scanner, on top of go/scanner templates.go three //go:embed declarations *.toml.tmpl the three starter files a project gets, embedded ``` About four hundred lines. There is no `internal/app`, no `internal/ui`, no `internal/buffer` — those exist once, in the library, and every editor built on it uses them unchanged. ## What `main` does Six things, in this order: 1. Parses the flags. 2. Calls `golang.Register()`, which teaches the library to colour `.go` files. 3. Builds `golang.Profile()` — the value that says this editor is Turbo Go. 4. Reads `.turbo-go/settings.toml` from the working directory, if there is one. 5. Opens the terminal and hands the screen, the theme name and the profile to `app.New`. 6. Starts gopls in the module root, and runs the event loop. That is the whole command. Every decision it makes — which theme wins, which files to open, whether to start a language server — is about *this run*, not about Go. ## The profile is the seam ```go profile.Profile{ Name: "Turbo Go", Slug: "turbo-go", Language: "Go", ToolsMenu: "~G~o", RootMarkers: []string{"go.mod"}, Server: profile.Server{Command: "gopls", Args: []string{"serve"}, …}, Templates: profile.Templates{Settings: …, Snippets: …, Tools: …}, } ``` Everything that used to be a hardcoded `"turbo-go"`, `"gopls"` or `"go.mod"` somewhere in eleven thousand lines is one field here. The library reads them; nothing in the library knows what any of them mean. `Slug` carries more than it looks. The binary is `turbo-go`, the project directory is `.turbo-go`, the user's own configuration lives in `~/.config/turbo-go`, and the environment variables that override it are `TURBO_GO_THEME_DIR` and `TURBO_GO_SNIPPET_DIR` — all derived from that one word. Those names are unchanged by the refactoring, deliberately: somebody who set `TURBO_GO_THEME_DIR` did so against a released binary. ## Why the Go scanner is here and not in the library turbo-core colours eight languages itself: TOML, YAML, Markdown, JavaScript, HTML, XML, Dockerfiles and shell. Those are the ones every editor meets whatever it is for — a project's configuration is TOML or YAML, its documentation is Markdown, its scripts are shell, its image build a Dockerfile. Go is not one of them. The language that *defines* an editor is registered by that editor, which is why a `.rs` file opens as plain text here and a `.go` file opens as plain text in Turbo Rust. The Go scanner is also the one that is *least* like the others. Every language in the library is scanned a line at a time with `syntax.LineScanner`; Go goes through `go/scanner`, the lexer the Go toolchain itself uses, and converts its byte offsets with `syntax.LineIndex`. That the library supports both shapes is because of this scanner. ## What moved, and what did not | Was | Is | | --- | --- | | `internal/buffer`, `internal/ui`, `internal/editor`, … | `turbo-core/buffer`, `turbo-core/ui`, `turbo-core/editor`, … | | `internal/syntax` — six languages | `turbo-core/syntax` — eight, plus a registry; Go lives here | | `internal/app` with a `Name` constant | `turbo-core/app` taking a `profile.Profile` | | `internal/lsp` hardcoding gopls | `turbo-core/lsp` taking a `profile.Server` | | `moduleRoot` in `main.go` | `app.ProjectRoot(p, files)`, with `go.mod` in the profile | | `settings.DirName = ".turbo-go"` | `p.ProjectDir()` | **Nothing about the editor's behaviour changed.** The menus, the keys, the themes, the file formats and the environment variables are what they were. What changed is where the code lives. ## Why a library rather than a fork The alternative to extracting turbo-core was copying Turbo Go and changing the Go bits. It was rejected before it was started: two copies of eleven thousand lines drift within a month, and every fix has to be made twice by somebody who remembers there are two. The cost, accepted: a change to a menu now affects every editor at once, and Turbo Go can no longer make a decision that suits only Go without either putting it in the profile or arguing for it in the library. That is a real constraint, and it is the one that keeps the editors the same editor. ## How it relates to the rest - What each of the library's packages does: [turbo-core's package reference](https://rickub.com/turbo-editors/turbo-core/blob/main/docs/en/reference/packages.md) - How the colouring works here: [Colouring and completion](colouring-and-completion.md) - Why the tools menu is data: [Go tools](go-tools.md) - The decisions that outlived the refactoring: [Design decisions](design-decisions.md)