Skip to content

umwelt-ai/rust-reorder

Repository files navigation

rust-reorder

CI License: MIT

Reorder top-level items in Rust source files from the command line.

Parses .rs files with syn, assigns each top-level item a numeric ordinal, and lets you rearrange them via list, move, and order commands. Comments travel with their associated items. A safety check guarantees no non-empty lines are lost or duplicated.

Install

Homebrew

brew install umwelt-ai/tap/rust-reorder

Cargo

cargo install rust-reorder

From source

git clone https://github.com/umwelt-ai/rust-reorder.git
cd rust-reorder
cargo build --release

The binary is at target/release/rust-reorder.

CLI Reference

rust-reorder <COMMAND>

Commands:
  list   List top-level items with their ordinals
  move   Move one item to a new position
  order  Fully reorder items by specifying all ordinals in the desired order

list

rust-reorder list <FILE>

Prints each top-level item with its ordinal, kind, and name. Output is tab-separated (ORDINAL\tKIND\tNAME), designed for scripting.

$ rust-reorder list src/lib.rs
0	use	std::fmt
1	struct	Config
2	impl	Config
3	impl	Display for Config
4	fn	main

move

rust-reorder move <FILE> <ORDINAL> --after <ORDINAL>
rust-reorder move <FILE> <ORDINAL> --before <ORDINAL>

Moves the item at the given ordinal to a new position relative to another item. Exactly one of --after or --before must be specified. The file is modified in place (atomically).

# Move item 4 to after item 0
rust-reorder move src/lib.rs 4 --after 0

# Move item 4 to before item 1
rust-reorder move src/lib.rs 4 --before 1

order

rust-reorder order <FILE> <ORDINALS>

Specifies the complete output order as a comma-separated list of ordinals. Every ordinal must appear exactly once.

rust-reorder order src/lib.rs 4,0,1,2,3

Item types

Every top-level syn::Item variant is recognized:

Syntax Kind Name
fn main() fn main
pub async fn serve() fn serve
struct Config struct Config
enum ErrorKind enum ErrorKind
trait Parser trait Parser
impl Config impl Config
impl Display for Config impl Display for Config
impl<T> From<T> for Config impl From for Config
const MAX: usize = 10 const MAX
static GLOBAL: Mutex<...> static GLOBAL
type Result<T> = ... type Result
mod tests mod tests
use std::io use std::io
extern crate alloc extern crate alloc
extern "C" { ... } extern "C"
union MyUnion union MyUnion
macro_rules! my_macro macro my_macro

Visibility (pub, pub(crate)), async, and generics are stripped from names. impl names show the trait and self type without generic parameters.

How it works

  1. Parse. syn::parse_file produces an AST. Each item's byte range is extracted from proc_macro2 span locations.

  2. Pin comments. The gap between consecutive items (blank lines, // comments) is attached to the item below it. Doc comments (///) and attributes (#[...]) are part of the syn span and don't need separate handling.

  3. Identify regions. Inner attributes (#![...]) and module doc comments (//!) at the top of the file form the preamble. Content after the last item forms the trailer. Both are preserved in place and never reordered.

  4. Compute permutation. move builds a permutation by removing the source item and reinserting it at the target position. order takes the permutation directly from the user.

  5. Emit. The output is assembled by slicing the original source string according to the permutation. No content is generated — only sliced and rearranged.

  6. Safety check. Before writing, the multiset of non-empty lines in the output is compared against the original. If they differ, the operation is aborted.

  7. Atomic write. A tempfile is created in the same directory as the target, written, flushed, then atomically renamed over the original.

Error handling

The tool fails immediately on:

  • Syn parse failure (invalid Rust syntax)
  • Non-UTF-8 input
  • Out-of-range ordinals
  • Same source and anchor in move
  • Missing, duplicate, or out-of-range ordinals in order
  • Safety invariant violation
  • File not found

Error messages include the specific values involved and what was expected:

Error: ordinal 99 is out of range: file has 6 items (valid: 0..5)
Error: duplicate ordinal 1: each item must appear exactly once
Error: expected 6 ordinals, got 3: all items must be listed exactly once

Limitations

  • Top-level items only. Nested items (e.g. functions inside impl blocks) are not individually addressable.
  • No \r\n support. Files with Windows line endings may not round-trip correctly.
  • Grouped use imports (use std::{io, fmt}) show {...} as the name portion.
  • Non-path self types in impl blocks (e.g. impl (i32, i32)) show unknown.
  • Files without a trailing newline may gain one after reordering.
  • No dry-run mode. The move and order commands modify the file in place.

Testing

cargo test

Unit tests cover parsing, permutation logic, emission, and safety checks. Integration tests exercise the CLI binary via std::process::Command.

License

MIT

About

Reorder top-level items in Rust source files. Designed for AI coding agents.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages