| 📦 Turbo Rust 713ea5c k33g 10h ago | 1 | # How to run cargo commands from the editor |
| 2 | |
| 3 | This guide shows how to format, lint, build, test and run your project without leaving Turbo Rust. It assumes the editor is installed and you have a Rust crate. |
| 4 | |
| 5 | ## Get a starter file |
| 6 | |
| 7 | Start the editor **from the project's own directory**, then choose **Rust ▸ Create tools file** (`Alt-T`, then `C`). |
| 8 | |
| 9 | That writes `.turbo-rust/tools.toml` with the five commands a Rust project runs before it commits, and opens it: |
| 10 | |
| 11 | ```toml |
| 12 | [[tool]] |
| 13 | name = "~F~ormat" |
| 14 | command = "cargo fmt" |
| 15 | output = "popup" |
| 16 | |
| 17 | [[tool]] |
| 18 | name = "~T~est" |
| 19 | command = "cargo test" |
| 20 | output = "popup" |
| 21 | |
| 22 | [[tool]] |
| 23 | name = "~R~un" |
| 24 | command = "cargo run" |
| 25 | # A terminal, not a popup: a program that reads the keyboard has to be able to |
| 26 | # be answered, and one that runs long has to be able to be interrupted. |
| 27 | output = "terminal" |
| 28 | ``` |
| 29 | |
| 30 | Each `[[tool]]` becomes one line of the **Rust** menu, in the order they appear — unless it names a `menu` of its own, which the next-but-one section covers. The file is read every time the menu opens, so an edit takes effect immediately. |
| 31 | |
| 32 | ## Run one |
| 33 | |
| 34 | `Alt-T`, then the letter between the tildes — `F` to format, `T` to test. |
| 35 | |
| 36 | A **popup** opens at once and fills in as the command runs. Its title carries the command and, once it has ended, how it went: |
| 37 | |
| 38 | ``` |
| 39 | ┌──────────── cargo clippy --all-targets — exit 1 ────────────┐ |
| 40 | │ main.rs:6:2: unreachable code │ |
| 41 | │ │ |
| 42 | │ [ Close ] │ |
| 43 | └───────────────────────────────────────────────┘ |
| 44 | ``` |
| 45 | |
| 46 | | Key | Effect | |
| 47 | | --- | --- | |
| 48 | | `↑` `↓` `PgUp` `PgDn` `Home` `End` | Read through the output | |
| 49 | | `Escape` | Close it — and **stop the command** if it is still running | |
| 50 | | `Enter` | Close it | |
| 51 | |
| 52 | A command that succeeded silently shows `(no output)` rather than a blank box, so you can tell it from one that has not started. |
| 53 | |
| 54 | The popup follows the output as it arrives until you scroll back, and then leaves you where you are. |
| 55 | |
| 56 | ## Choose where the output goes |
| 57 | |
| 58 | Set `output` on a tool: |
| 59 | |
| 60 | | `output` | What you get | |
| 61 | | --- | --- | |
| 62 | | `popup` | A dialog that fills in as it runs. The default. | |
| 63 | | `terminal` | A terminal window: colours, `Ctrl-C`, and the keyboard reaches the program | |
| 64 | | `editor` | An editing window once it has finished, to search with `Ctrl-F` | |
| 65 | |
| 66 | `Run` is `terminal` in the starter file, and it is the example of why the key exists: a popup cannot answer a program that reads from the keyboard, and cannot be interrupted with `Ctrl-C`. |
| 67 | |
| 68 | Reach for `editor` when the output is something to work through — a long `go test -v`, or a coverage report you want to search. |
| 69 | |
| 70 | ## A long command holds the editor |
| 71 | |
| 72 | A popup is modal: while `go build` runs, you cannot type anywhere else. `Escape` closes it and stops the command. |
| 73 | |
| 74 | If that gets in the way for a particular command, give it `output = "terminal"` — the window is an ordinary one and you can carry on working beside it. That is what making the key configurable is for. |
| 75 | |
| 76 | ## What happens to your open files |
| 77 | |
| 78 | `Format` rewrites files on disk — including the one you are looking at. When a command finishes, the editor **re-reads every open file that has no unsaved changes**, so the formatted version appears without you doing anything. The status bar says how many. |
| 79 | |
| 80 | A file with unsaved changes is **left alone**, and the status bar says so too: |
| 81 | |
| 82 | ``` |
| 83 | Reloaded 2 files; 1 file with unsaved changes left alone |
| 84 | ``` |
| 85 | |
| 86 | That is deliberate: your edit and the formatter genuinely disagree, and the editor is not the one that should decide which wins. Save first (`F2`) and run the command again, or keep editing and format later. |
| 87 | |
| 88 | ## Add your own commands |
| 89 | |
| 90 | Edit `.turbo-rust/tools.toml`. A command goes to `sh -c`, so one entry can be a whole sequence: |
| 91 | |
| 92 | ```toml |
| 93 | [[tool]] |
| 94 | name = "~C~heck" |
| 95 | command = "cargo fmt && cargo clippy --all-targets && cargo test" |
| 96 | output = "popup" |
| 97 | |
| 98 | [[tool]] |
| 99 | name = "Tid~y~" |
| 100 | command = "cargo update" |
| 101 | output = "popup" |
| 102 | |
| 103 | [[tool]] |
| 104 | name = "Cover~a~ge" |
| 105 | command = "go test -coverprofile=cover.out ./... && go tool cover -func=cover.out" |
| 106 | output = "editor" |
| 107 | ``` |
| 108 | |
| 109 | Give each a hot key with tildes, and keep them distinct — the menu answers the first match it finds. |
| 110 | |
| 111 | ## Put a tool in a menu of its own |
| 112 | |
| 113 | A tool that has nothing to do with Rust does not belong in the Rust menu. Give it a `menu`: |
| 114 | |
| 115 | ```toml |
| 116 | [[tool]] |
| 117 | name = "~E~cho" |
| 118 | command = "echo TADA" |
| 119 | output = "terminal" |
| 120 | menu = "Tools" |
| 121 | |
| 122 | [[tool]] |
| 123 | name = "~U~p" |
| 124 | command = "docker compose up -d" |
| 125 | menu = "Docker" |
| 126 | |
| 127 | [[tool]] |
| 128 | name = "~D~own" |
| 129 | command = "docker compose down" |
| 130 | menu = "Docker" |
| 131 | ``` |
| 132 | |
| 133 | That gives you a **Tools** menu and a **Docker** menu on the bar, between Rust and Help, in the order the names first appear in the file. Docker holds both its tools. Nothing needs restarting: save the file and the bar follows. |
| 134 | |
| 135 | The name is yours to choose — there is no list to pick from. Leave `menu` out and the tool stays in Rust, which is where all five starter commands are. |
| 136 | |
| 137 | ### The hot key is chosen for you |
| 138 | |
| 139 | You cannot know, when writing the file, which letters the editor's own menus have taken. So it works it out: the first letter of the name that nothing else claims gets the tildes. |
| 140 | |
| 141 | `Tools` gets `Alt-T`. `Format` gets `Alt-M`, because `F` is File's, `o` is Options' and `r` is Run's. |
| 142 | |
| 143 | Write the tildes yourself — `menu = "Doc~k~er"` — and a free letter is kept. A taken one is not: the bar answers the *first* menu matching a key, so honouring your choice would make one of the two menus unreachable. It picks another letter and says nothing. |
| 144 | |
| 145 | ## Variants |
| 146 | |
| 147 | - **You want `golangci-lint` instead of `go vet`.** Change the `Lint` command. `go vet` is the default because it ships with the toolchain and is never missing; anything else you have to install. |
| 148 | - **You started the editor from a subdirectory.** Commands run there, so `./...` covers only that subtree. Start from the project root. |
| 149 | - **The file has a mistake in it.** The menu shows a greyed-out `Cannot read tools` where the commands would be, and **Create tools file** is still there. |
| 150 | - **A command is not installed.** The popup shows `command not found` and `— exit 127`, which is what a shell would have said. |
| 151 | - **You want a menu named after one that exists.** `menu = "File"` gives you a second File menu, further along the bar, with a different hot key. Nothing stops you; nothing recommends it either. |
| 152 | - **Your menu has no hot key.** Every letter in its name was already taken. `F10` and the arrow keys reach it, and so does the mouse. Rename it to something with a free letter. |
| 153 | - **You misspelt `output`'s value.** The whole file is refused and the menu says `Cannot read tools`, naming the tool and listing what it could have been. A silent fallback would have sent the output somewhere you did not ask for. |
| 154 | |
| 155 | ## Ask for a value when the command runs |
| 156 | |
| 157 | Some commands need something typed each time: a module path, a crate name, a test to filter on. Put a `{{label}}` where the value goes: |
| 158 | |
| 159 | ```toml |
| 160 | [[tool]] |
| 161 | name = "~I~nit module" |
| 162 | command = "cargo new --bin {{crate name}}" |
| 163 | output = "popup" |
| 164 | ``` |
| 165 | |
| 166 | Choosing it now opens a box titled **Init module** with one field, labelled `module path`. Type the value and press Enter; the command runs with it. Escape, and nothing runs. |
| 167 | |
| 168 | The value is quoted, so a path with a space in it stays one argument. |
| 169 | |
| 170 | ### Several values at once |
| 171 | |
| 172 | One field each, in the order they appear: |
| 173 | |
| 174 | ```toml |
| 175 | [[tool]] |
| 176 | name = "~C~opy" |
| 177 | command = "cp {{from}} {{to}}" |
| 178 | ``` |
| 179 | |
| 180 | **Tab** moves between the fields, **Enter** runs it. |
| 181 | |
| 182 | ### One field standing for several arguments |
| 183 | |
| 184 | Quoting is wrong when you mean "put these flags on the end". Add `...` inside the braces and the value goes in verbatim: |
| 185 | |
| 186 | ```toml |
| 187 | [[tool]] |
| 188 | name = "Test ~o~ne" |
| 189 | command = "cargo test {{extra flags...}}" |
| 190 | ``` |
| 191 | |
| 192 | Type `--release parse` and all of it reaches the command as separate arguments. |
| 193 | |
| 194 | ### The same value twice |
| 195 | |
| 196 | Write the label twice; you are asked once: |
| 197 | |
| 198 | ```toml |
| 199 | [[tool]] |
| 200 | name = "~N~ew directory" |
| 201 | command = "mkdir {{name}} && cd {{name}}" |
| 202 | ``` |
| 203 | |
| 204 | ### Variants |
| 205 | |
| 206 | - **The value is the same most times.** Run it once and the box remembers what you typed, for the rest of the session. It is not written to disk. |
| 207 | - **Your command has braces in it already.** `awk '{print $1}'` and `find . -exec rm {} +` are left alone: only double braces ask for anything. |
| 208 | - **The command asks for more values than fit on screen.** The editor says so rather than opening a box whose OK button is below the bottom of the terminal. Make the terminal taller, or split the command into two tools. |
| 209 | |
| 210 | ## See also |
| 211 | |
| 212 | - Every key of the file and every rule: [Rust tools reference](../reference/rust-tools.md) |
| 213 | - Why each command gets a terminal window, and why an unmodified file reloads: [Rust tools](../explanation/rust-tools.md) |
| 214 | - The windows the commands run in: [Terminal windows](../reference/terminal.md) |