بِسْمِ ٱللَّهِ ٱلرَّحْمَـٰنِ ٱلرَّحِيمِ
Commands
Every refac command with its arguments, the rules per language, and examples.
Help comes in three depths, all printed from inside the binary, so it is there when this site is not:
refac move -h # a few lines: what the command is and its flags
refac move --help # everything about one command: arguments, rules, output, examples
refac guide # in-depth topics: languages, safety, batching, kotlin, output, serversrefac --help is the whole tool on one page. This page gives you the same map with the details in reach.
| Command | Does |
|---|---|
move | Moves or renames files and folders and rewrites every import, module line, package line, and Markdown link that pointed at them |
move-module | Moves a whole Rust module subtree and every crate:: path to it |
rename | Renames a symbol and every reference to it |
doctor | Checks the language servers refac starts and prints how to install a missing one |
guide | Prints in-depth documentation by topic |
completions, man | Print shell completions and the manual page |
move
refac move [OPTIONS] (--source-path <PATH>... --target-path <PATH>... | --batch <FILE>)| Option | Meaning |
|---|---|
--project-path DIR | The package root of the language. Defaults to the current directory. Environment: REFAC_PROJECT_PATH |
--source-path PATH... | A file or folder to move, absolute or relative to --project-path. Repeat for several |
--target-path PATH... | Where it goes. A folder in the path that does not exist yet is created. The n-th source goes to the n-th target |
--batch FILE | The moves as a JSON list instead of flags, - for stdin. Replaces --source-path and --target-path |
--dry-run | Plan the move, print what it would do, and change no file |
--allow-single | Kotlin only: let a single Kotlin change through, which is refused by default |
--json | Print one JSON document instead of text |
The --batch file holds [{"source_path": "a.kt", "target_path": "pkg/a.kt"}, ...]. Each entry has exactly those two keys.
Rules by language
| Language | Rule |
|---|---|
| TypeScript / JavaScript | Folders can be moved. At most 30 source files per call. The tsconfig decides which files are callers |
| Kotlin / Android | Needs the Kotlin language server. Every call imports the Gradle build (about 24 s), so put all moves in one call. .java files, folders that contain Java, and moves between modules or source sets are refused |
| Go | Moving a file to another folder moves the whole package. The output lists the files that moved with it |
| Rust | A .rs file can be renamed inside its folder. A cross-folder target is refused and points at move-module |
| Python | Rope rewrites the imports, with Pyrefly as the fallback. Imports through an __init__.py re-export may be missed |
| Dart | dart pub get must have run. A move that would leave a package: import pointing at a missing file is refused |
| Markdown | Files, images, other assets, and folders. Code blocks, comments, and ignored files are left alone |
Preview
--dry-run plans the same move and changes no file. Per language it prints the paths that would move, then one // <file> (N edits) line per file that would be edited, then the notes. It runs the same checks and refuses what the move refuses, with exit code 1 and the same report. Python (Rope) and Kotlin cannot plan without moving, so they run the real move on a throw-away copy of the project (limit 500 MiB, REFAC_DRY_RUN_COPY_MAX_MB) and report the difference.
move-module
refac move-module [OPTIONS] <SOURCE_MODULE> <TARGET_MODULE>| Argument or option | Meaning |
|---|---|
SOURCE_MODULE | The module as it is now, starting with crate:: |
TARGET_MODULE | The module as it should be, starting with crate:: and in the same crate |
--project-path DIR | A Cargo package or workspace root. Defaults to the current directory |
--dry-run | Plan the move and change no file. It does not compile the result |
--check | With --dry-run: also run cargo check --workspace --all-targets on a throw-away copy of the workspace. It is refused without --dry-run |
--json | One JSON document |
See the Rust page for what is rewritten and refused.
rename
refac rename [OPTIONS]The language comes from the extension of --file:
| Extensions | Language | Done by |
|---|---|---|
.ts .tsx .js .jsx .mts .cts .mjs .cjs | TypeScript / JavaScript | Oxc and the TypeScript native language server |
.kt | Kotlin / Java | The JetBrains Kotlin language server, plus Android XML |
.go | Go | gopls |
.rs | Rust | rust-analyzer |
.py | Python | basedpyright |
.dart | Dart | The Dart SDK analysis server |
| Option | Meaning |
|---|---|
--project-path DIR | The root the language server loads. Defaults to the current directory |
--file FILE | The file that contains the symbol, absolute or relative to --project-path |
--symbol NAME | The current name, written exactly as in that file |
--new-name NAME | The new name. It must be a plain identifier and not a keyword of the language |
--line N, --column N | Pick one symbol when the name means several in the file. --column is a 1-based byte column, like rg --column |
--batch FILE | Several renames in one server session, all or nothing. A JSON list of file, symbol, new_name, and optional line and column. - is stdin |
--dry-run | Plan and prove the rename, print it, and change no file |
--allow-single | Kotlin only: let a single Kotlin change through |
--json | One JSON document |
Before anything is written
- The server plans the rename.
- refac proves it: the server is shown the renamed text in memory and must find exactly the places it found before. A new name that clashes with or shadows another declaration changes what a call means. That is refused, naming the places, and no file changes.
- Only then are the files written, through an undo journal.
Some names are refused before a server even starts: a name that is not a plain identifier, a keyword of the language, the current name itself, and for Python a special method such as __init__. The name of a module or package is refused with the hint to use refac move. A rename of a symbol that also lives in files outside the project is refused, because those packages would stop building.
When the name means several symbols in the file, nothing is renamed and the error lists every candidate with its line.
doctor
refac doctor # one line per language, no server started
refac doctor <language> # find, start, check, and stop one server<language> is one of go, rust, python, dart, kotlin, or typescript. Without a language, doctor prints ready, missing, or broken for each one and returns at once. With a language it finds the server exactly as a command would, starts it, makes it answer the handshake, stops it, and prints the version, the path, and the numbered steps that fix what is wrong.
| Option | Meaning |
|---|---|
--project-path DIR | The project the server will work in. rustup picks the Rust toolchain from there, and Python its environment |
--json | A JSON list with one object per language |
The exit code of refac doctor alone is 0. For refac doctor <language> it is 0 when the server is ready and 1 when it is missing or broken, so a script or an agent can branch on it.
guide
refac guide # list the topics
refac guide languages # one topic
refac guide all # every topic| Topic | Answers |
|---|---|
languages | What refac does in each language, and where it stops |
safety | What is checked, what is written, and what happens when something fails |
batching | What a command costs and how to do many changes with few server starts |
kotlin | Why a Kotlin change is slow, what it costs, and the options you have |
output | How to read the report, the JSON documents, and the exit codes |
servers | Which language servers are started, where they are found, and how to fix a missing one |
completions and man
refac completions bash > ~/.local/share/bash-completion/completions/refac
refac man | man -l -completions supports bash, elvish, fish, powershell, and zsh.