| 📦 Turbo Go 3d7798b k33g 9h ago | 1 | # Project tree — explanation |
| 2 | |
| 3 | ## What is this about? |
| 4 | |
| 5 | `F9` opens a window listing the project's files, and pressing `Enter` on one opens it. This page is about the three decisions inside that: where the tree is rooted, why it is a window rather than a panel down the side, and why it does not notice files appearing on its own. |
| 6 | |
| 7 | ## Why the root is the working directory |
| 8 | |
| 9 | The editor already contains two different answers to "what is the project". |
| 10 | |
| 11 | The language server walks up from the file you opened until it finds a `go.mod`, because a module has a real boundary — being inside one is a fact about the code, and gopls needs that exact directory to work in. The project settings file does not walk at all: `.turbo-go/settings.toml` is looked for in the working directory and nowhere else. |
| 12 | |
| 13 | The tree follows the settings file, and it is worth saying why the *other* rule was tempting. Walking up to the `go.mod` would mean that opening a file from anywhere in a project shows the whole project, which is what an explorer usually does. But it also means the tree's root depends on a file three directories away that you may not have thought about, and it stops being predictable the moment a repository holds more than one module — a monorepo would show you whichever module the file you happened to open belongs to. |
| 14 | |
| 15 | The rule kept is the one that can be said in a sentence and is true everywhere in the editor: **the project is the directory you started the editor in.** It costs something, and the cost is named in the [how-to](../how-to/browse-a-project.md): start from a subdirectory and you get a tree of that subdirectory. The answer is to start from the project root, which is where you would run `go build` and `git` anyway. |
| 16 | |
| 17 | ## Why `.git` is hidden and nothing else is |
| 18 | |
| 19 | The Open dialog hides every entry beginning with a dot. Copying that here was the obvious thing and would have been wrong. |
| 20 | |
| 21 | `.turbo-go/settings.toml` is a file this editor asks people to edit — it is why the editor colours TOML at all. `.gitignore` and `.qlty/qlty.toml` are files of the project too. A tree that hid them would make the editor's own configuration unreachable from the editor's own file browser, which is an odd place to end up. |
| 22 | |
| 23 | `.git` is different in kind rather than in spelling: nothing inside it is meant to be opened by hand, and it holds enough objects to bury everything else in the listing. One name, hidden for a reason that can be stated. Respecting `.gitignore` as well was considered and turned down for now: it would hide `bin/` and `release/`, which is genuinely nicer, and it costs a gitignore pattern engine — negation, `**`, anchoring — that is a feature in its own right rather than a detail of a tree. |
| 24 | |
| 25 | ## Why it is a window, not a panel |
| 26 | |
| 27 | Every other editor puts its file tree in a fixed strip down the left. That was the alternative, and it was turned down because of what it would have cost the rest of the editor. |
| 28 | |
| 29 | A docked panel means the desktop is no longer a single rectangle that windows live in. `Desktop` would need a notion of reserved edges; `Window.fitInto` and the grow modes would have to respect them; maximising would mean "the whole desktop except the panel"; tiling and cascading would need to know about it. That is a change to the foundation of the whole interface, for one widget. |
| 30 | |
| 31 | As an ordinary window, the tree gets everything for free and behaves like everything else: `F6` reaches it, `Alt-2` raises it, `[x]` closes it, `[■]` fills the desktop with it, **Window ▸ Tile** puts it beside your file. Nothing in `ui` had to change. If a docked panel is wanted later, it is a `ui` feature to be designed on its own terms rather than something smuggled in with a file browser. |
| 32 | |
| 33 | ## Why there is only one |
| 34 | |
| 35 | Two trees on the same project would be two views of one thing with nothing to tell them apart, and the project cannot change while the editor runs — the root is fixed at start-up. So `F9` on an open tree raises it rather than making another, the same way opening a file that is already open raises its window. |
| 36 | |
| 37 | ## Why it does not watch the disk |
| 38 | |
| 39 | A tree that noticed `go build` producing `bin/` would be better. Doing it properly means watching the filesystem, and in Go that means `fsnotify` — a third dependency, against a project that has kept to two since it started and treats adding one as a decision to be argued for. |
| 40 | |
| 41 | It is not a small dependency in behaviour either: recursive watches, watch descriptors running out on large trees, and different semantics on every platform, in a feature whose failure mode is a stale line in a list. |
| 42 | |
| 43 | So the tree re-reads on demand, and the editor picks the moments it can be sure about. Saving a file is one: the editor did it, so it knows. `F5` and `Ctrl-R` are the other, because a build in a terminal window is something only the user knows has finished. Refreshing keeps the shape of the tree and re-reads only the directories that were actually opened, so it costs what is on screen rather than a walk of the project. |
| 44 | |
| 45 | ## Why the tree has theme keys of its own |
| 46 | |
| 47 | The obvious economy was to draw it with the `list.*` keys — a tree is a list, after all, and it would have meant no new keys for user themes to miss. |
| 48 | |
| 49 | It does not work, and the reason is worth recording. `list.selected` is coloured to stand out against a **dialog**. In `turbo-classic` it is white on navy, and `window.body` is silver on **navy** — a tree in a window would have highlighted its selected row in exactly the background colour it sits on. The selection would have been invisible in the theme the editor ships as its default. |
| 50 | |
| 51 | So `tree.text`, `tree.directory`, `tree.selected` and `tree.unfocused` exist, and a test holds every shipped theme to a minimum contrast between the first and the third, in the same way the cursor colours are checked. A user theme that sets none of them falls back along the dots to `default`: a readable tree without the file-and-directory distinction, rather than nothing at all. |
| 52 | |
| 53 | ## How it relates to the rest |
| 54 | |
| 55 | - Every key and every rule, exactly: [Project tree reference](../reference/project-tree.md) |
| 56 | - Using it: [How to browse a project and open files from a tree](../how-to/browse-a-project.md) |
| 57 | - The other place "the project" is defined the same way: [Project settings](project-settings.md) |
| 58 | - Where `filetree` sits among the packages: [Architecture](architecture.md) |