# Project tree — explanation ## What is this about? `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. ## Why the root is the working directory The editor already contains two different answers to "what is the project". The language server walks up from the file you opened until it finds a `pyproject.toml`, because a module has a real boundary — being inside one is a fact about the code, and pylsp needs that exact directory to work in. The project settings file does not walk at all: `.turbo-python/settings.toml` is looked for in the working directory and nowhere else. The tree follows the settings file, and it is worth saying why the *other* rule was tempting. Walking up to the `pyproject.toml` 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. 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. ## Why `.git` is hidden and nothing else is The Open dialog hides every entry beginning with a dot. Copying that here was the obvious thing and would have been wrong. `.turbo-python/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. `.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. ## Why it is a window, not a panel 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. 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. 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. ## Why there is only one 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. ## Why it does not watch the disk 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. 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. 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. ## Why the tree has theme keys of its own 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. 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. 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. ## How it relates to the rest - Every key and every rule, exactly: [Project tree reference](../reference/project-tree.md) - Using it: [How to browse a project and open files from a tree](../how-to/browse-a-project.md) - The other place "the project" is defined the same way: [Project settings](project-settings.md) - Where `filetree` sits among the packages: [Architecture](architecture.md)