Formatting by Language

How to indent Rust code on Mac

You can do this with Note My — here is how to put a .rs file back to four-space blocks and aligned match arms in one pass, and which controls in the Indentation sheet actually do it.

Rust has a strong shape. Four spaces per level, the opening brace on the same line, match arms lined up under one another with a comma after each, a long where clause broken across lines. A file that has been pasted out of a browser, merged badly, or written at speed in three tools stops looking like that — and once it does, a match expression becomes hard to read at all.

This guide covers how to re-indent a .rs file in Note My, which settings in the Indentation sheet apply to Rust, and what the pass keeps exactly as you wrote it.

What one re-indent pass changes in a .rs file

Our indentation engine does more than shift lines sideways. It puts every block at the right depth, applies your brace style, and unpacks statements squeezed onto a single line. Rust is one of fifteen languages it treats specifically, so match arms and where clauses come back in the shape Rust expects. It all happens on your Mac — nothing is uploaded, and there is no account.

The defaults are already close to the Rust convention, which is why most people never change them:

Indentation defaults as they apply to a Rust file
SettingDefaultNotes
Indent width4Sheet range 1–12
Tabs or spacesSpacesYours to set for Rust, and remembered once you do; Go and Python carry locks of their own
Brace styleSame line (K&R)Next line (Allman) is the other choice
Trailing comma on match armsOnA Rust-specific option in the sheet
Recover damaged commentsOffGlobal, and deliberately opt-in

So Rust is ready to go the moment you open the sheet. It follows the global width and tabs-or-spaces setting, which already default to four spaces — the Rust convention exactly. Set them differently with Rust selected and the choice is remembered for Rust from then on.

Re-indent a Rust file

  1. Save the file first

    Press ⌘S. A re-indent changes the whole file in one go, and the dependable way back is ⌘R — File ▸ Reload from Disk — which sets aside what is on screen and reopens the file exactly as it sits on disk. Reloading never changes the file on disk, so it costs you nothing: save first and there is always a clean copy to return to.

    Save, then experiment freely. With that saved version underneath you, try four spaces against two, or same-line braces against next-line, and reload your way back to the starting point as often as you like. Our auto-recovery safety net sits behind all of it, holding your work for the day the Mac restarts under you.

  2. Check Note My knows it is Rust

    The status bar shows the language in use. A file saved as lib.rs is never in doubt, and our advanced language identifier puts the rest on the right language without you doing anything. A short fragment pasted into an untitled tab is worth a glance before you go further, and confirming it takes a second. The Rust controls come into their own once the file is treated as Rust, and that one glance is the whole of what they ask of you.

    Click the Identify pill to open the Language Inspector, which reports "Identified programming language: X" and lets you override it.

  3. Open the Indentation sheet

    Click Indent in the toolbar — the braces glyph. Everything a re-indent can do lives behind that one button, so there is nothing to go hunting for. It opens a sheet and reformats nothing on its own: you settle on the shape you want first, and the file moves only when you say so.

  4. Choose Rust in the language picker

    The picker offers a global default plus fifteen languages. Selecting Rust snaps the brace style, width and tabs-or-spaces controls to the values stored for Rust, and reveals the Rust section below the general controls.

  5. Check the brace style and the Rust controls

    There are exactly two brace styles: same line and next line. Rust uses same line, which is the default. Two further options are specific to Rust — the trailing comma on match arms, and where clause wrapping — both covered below.

  6. Press Apply

    Nothing changes until you do. Apply also persists the settings, so the next file starts where this one finished. Cancel, or ⎋, saves neither.

Trailing commas on match arms

A trailing comma after the last arm of a match is idiomatic Rust for a practical reason: adding an arm later is then a one-line diff. The Rust section carries a match trailing-comma option, and it is on by default.

rust
match message {
    Message::Quit => break,
    Message::Move { x, y } => self.move_to(x, y),
    Message::Write(text) => self.write(&text),
}

Arms are also where the pass earns its keep: they are where a badly merged file goes wrong first, and arms at inconsistent depths hide the shape of the enum entirely.

Wrapping long where clauses

The second Rust-specific option is where clause wrapping. Rust's own convention breaks a long bound list so each constraint sits on its own line under the where:

rust
fn merge<K, V>(left: Map<K, V>, right: Map<K, V>) -> Map<K, V>
where
    K: Eq + Hash + Clone,
    V: Clone,
{
    left.into_iter().chain(right).collect()
}
Note

Give the wrapping controls a moment while you are in the sheet — several of them are column limits, and a column limit sits at 0, meaning off, until you name a column of your own. Set the one your project works to and long lines break where you want them to.

Worth knowing as you set these: brace style, indent width and tabs-or-spaces are stored per language, so Rust can hold four spaces and same-line braces while another language you work in holds something else entirely. The rest of the sheet, these two Rust options included, applies across the board — decisions you make once and then carry into every file you open. "Reset to global" clears the three per-language settings and leaves the rest exactly as you set them.

Statements that share a line get unpacked

The pass is not limited to leading whitespace. A function compressed onto one line comes back as a block:

rust
fn main() { let x = 1; println!("{x}"); }

becomes

rust
fn main() {
    let x = 1;
    println!("{x}");
}

Comments: doc comments and nested blocks

Ordinary comments are re-indented with the code around them. Two Rust-specific points matter.

Doc comments are never split or un-commented. The markers ///, //!, /** and /*! are always left alone, so a crate-level //! header and your item docs move with the code they sit against but are never taken apart. You can re-indent a documented crate without proof-reading the docs afterwards.

Nested block comments stay nested. Rust is one of the few languages where /* /* */ */ is legal, and a nested block comes through a re-indent intact: the outer comment still ends where you closed it, not at the first inner */. Swift and Kotlin behave the same way. Our hidden-character scanner is careful in the same spirit: anything odd it finds inside a comment is reported for you to judge rather than swept up on your behalf, so a chunk of code you have parked behind a comment marker stays exactly as you left it.

rust
/* disabled for now
   /* including this inner block */
   still inside the outer comment */

The optional comment-recovery pass

The sheet carries a Recover damaged comments checkbox, off by default. It fixes one kind of damage: a line where a comment marker has swallowed real code, so // keep state let x = 1 is one commented line where it should be a comment and a statement. Rust is one of the thirteen languages it covers.

It is deliberately cautious, working a line at a time, and it stays out of the way until you ask for it. Turn it on for an inherited file with that damage, then turn it off again — it is a repair, not a routine.

Writing Rust, rather than fixing it

Smart editing. Return carries the current line's indentation onto the next line and adds one unit after a trailing {, [, ( or :. Six pairs auto-close: (), [], {}, "", '' and backticks. Angle brackets are deliberately left to you — the right call for Rust, since a generic parameter list and a comparison are the same character. Five switches govern it — a master plus one each for Return, brackets, quotes and tags — and all five are on by default. The master is the toolbar's Smart Edit toggle; the full set lives in Settings ▸ Editing.

Indentation guides. On by default, ten styles in Settings ▸ Guides, Dots as the default. They are drawn on screen, never inserted, so they add nothing to the file and nothing to a diff. On a tidy Rust file they fall on four-space steps, which makes a line that has drifted to two or six spaces obvious at a glance.

Folding, to check your work. Double-click a brace and everything between it and its partner collapses; double-click again to bring it back. Three pair types fold: {}, () and []. Folding each impl block is the quickest way to confirm every block closes where you expect, and it never modifies the document.

More you can do with a .rs file

  • Every re-indent is deliberate. The pass runs when you press Apply and at no other moment — never quietly on save, never in the background while you type. It settles depth, brace placement and statements squeezed onto one line, and applies the Rust options from the sheet, and that is the whole of what moves.
  • Macros get a colour of their own. Our syntax engine gives Rust macros their own shade, which makes a macro body sitting at the wrong depth easy to spot before you run the pass and easy to confirm afterwards. The colour is only ever on screen and is never written into the file.
  • Sweep a change across the whole file. Our find and replace works over the entire document, so a renamed variant across twenty match arms, or every call site you want to look over, is one search away — then re-indent to settle everything back into shape in a single pass.
  • See exactly what moved. Duplicate the .rs file in the Finder before you press Apply, then open both copies and read them side by side in our comparison view. On a file you have inherited, that is the quickest way to satisfy yourself that what changed was depth and bracing and nothing else.
  • Catch what arrived with a paste. Rust copied out of a browser often brings more than code with it. Our hidden-character scanner tells you what is in there and where, so you can clear it first and read the re-indented result with confidence.

Troubleshooting

I pressed Indent and nothing happened

The button opens the sheet; the sheet acts. Nothing changes until you press Apply. On an empty document there is nothing to change, so nothing appears to happen.

The result is indented, but wrongly

A re-indent always gives you a result — it takes the file as written, whatever state it has got into. That makes it a useful diagnostic in its own right: if a block comes back deeper than you expected, the file itself is carrying a brace too few or one too many. Reload from disk, then fold the top-level blocks one at a time. The first block that swallows more than it should is where the missing brace belongs.

It gave me spaces where I wanted tabs

Rust follows your global setting, which starts out as spaces at width 4. Go is locked to tabs and Python to four spaces; Rust is yours to decide. Choose tabs with Rust selected in the picker and the choice is stored for Rust from then on.

What the preview card is showing

The card shows a fixed if <condition> { … } snippet, redrawn live as you change the width, tabs and brace style. It gives you the shape of the settings at a glance, so you can see what four spaces and a same-line brace are going to look like before a single line of your own file moves.

A very large file takes a moment

A re-indent changes the whole file in one pass, so on a very large .rs file — a generated binding set, say — the window stays busy for a beat while it works. Give it that beat and it comes back finished, top to bottom. Our large-file engine keeps a big generated file comfortable to open, scroll and search; re-indenting one end to end is the deeper job, and the one worth waiting out.

A scan reported mixed tab and space indentation

Mixed tab/space indent is one of the twenty-one things our hidden-character scanner reports. It tells you the file has both, and where; it does not rewrite your indentation. A re-indent is what resolves it: pick Rust in the sheet, confirm spaces and width 4, and apply.

I only want to reformat one function

Run the pass over the whole document and read the part you came for. Every block settles to the same rules in one go, so the function you were worried about comes back in the shape you wanted and the lines you were not thinking about are tidied along with it. To see precisely what happened to that one function, duplicate the file in the Finder before you press Apply, then open the two copies together in our comparison view: your function is right there in context, with everything else that moved marked around it.

Frequently asked questions

Does re-indenting a Rust file add trailing commas to my match arms?

It is a Rust setting in the Indentation sheet and it is on by default, so yes, unless you turn it off. It is one of two Rust-specific controls; the other is where clause wrapping.

What happens to my /// and //! doc comments?

They come through exactly as you wrote them. Those markers are always left alone, so a crate-level header and your item docs travel with the code they belong to and are never taken apart. Block comments keep their markers too, and the comment-recovery option stays out of the way until you turn it on. Re-indent a documented crate and the prose is untouched.

Where do I find the re-indent controls?

In the toolbar. The Indent button — the braces glyph — opens the Indentation sheet, and everything a re-indent can do sits in that one place: width, tabs or spaces, brace style, the language picker and the two Rust options. One button to remember, and it opens the sheet rather than acting, so you settle the shape you want before a line of your file moves.

Can I set four spaces for Rust and tabs for another language?

Yes. Brace style, indent width and tabs-or-spaces are the three settings genuinely stored per language, so a change made with Rust selected applies to Rust alone.

Why did my pasted Rust snippet come out as generic C-style indentation?

Because the file was not yet being treated as Rust. You still get sensible general-purpose indentation — braces and depth come out right — and naming the language brings the match arms and where clauses along with them. Set it from the Identify pill, or pick Rust in the sheet, and run the pass again on the same file.

Does any of this send my code anywhere?

No. Note My has no account and no sign-in, and nothing is uploaded. Everything described here works on your Mac, and your .rs files never leave the machine.