Skip to content

bryceremick/rm-comments

Repository files navigation

rm-comments

AI agents: see llms.md for complete installation and usage instructions intended for LLMs.

Contents

Overview

rm-comments is a cli tool that quickly and safely removes comments from source code files.

Files are parsed using the tree-sitter crate rather than matched with regular expressions, so removal is done using the language's actual syntax.

Comment-like sequences inside string literals, regular expressions, and docstrings are never affected, and everything that is not a comment is preserved byte for byte.

The tool also ships with a rich set of arguments/options that provide granular control over exactly what comments are removed or kept from source files.

Installation Methods

Homebrew

brew trust bryceremick/tap
brew install bryceremick/tap/rm-comments

crates.io

cargo install rm-comments

cargo-binstall (prebuilt, no compile)

cargo binstall rm-comments

Prebuilt binaries

All platforms (incl. Windows), on the releases page.

From source

git clone https://github.com/bryceremick/rm-comments
cd rm-comments && cargo build --release

LLM Agent Plugins

These plugins do not include the binary, only a skill instructing your agent on how and when to utilize this tool.

Community contributions are welcome if you don't see your preferred agent here

Claude Code

/plugin marketplace add bryceremick/rm-comments
/plugin install rm-comments@rm-comments

Basic Usage

Individual files:

rm-comments src/main.rs

Directories:

rm-comments src/

Default Behavior

Before:

/// Loads the configuration from the given path.
fn load(path: &Path) -> Config {
    // TODO: validate the path exists before reading

    // First, read the contents of the file into a string.
    let s = read(path); // read the file
    /* Now that we have the string, we can parse it.
       The parse function takes the string and a key. */
    let cfg = parse(&s, "key // not a comment");
    
    // Finally, return the parsed configuration.
    cfg
}

After:

/// Loads the configuration from the given path.
fn load(path: &Path) -> Config {
    // TODO: validate the path exists before reading
    let s = read(path);
    let cfg = parse(&s, "key // not a comment");
    cfg
}

Command reference

rm-comments [OPTIONS] <FILE|DIR>              # strip in place (atomic write)
rm-comments [OPTIONS] --stdin --lang <NAME>   # read stdin, write stdout
rm-comments install-zed-task                  # add the Zed editor task
Flag Effect
--stdout Print the result instead of writing the file (file/stdin only)
--check, --dry-run Report only; exit 1 if changes would be made, 0 if clean
--stdin Read source from stdin, write to stdout; requires --lang
--lang <NAME> Language name or extension for --stdin (e.g. rust, py)
--strip-doc-comments Also remove doc comments (///, //!, /*!, /** */); kept by default
--strip-directives Also remove directive comments (eslint-disable, # noqa, …); kept by default
--strip-markers Also remove task markers (TODO, FIXME, HACK, XXX, BUG); kept by default
--keep <REGEX> Preserve comments matching REGEX (repeatable)
--lines <A-B> Restrict removal to a 1-based line range (repeatable; N = single line)
--list Print every comment as JSON; modifies nothing
--apply <IDS> Remove exactly these comma-separated --list ids; ignores keep policies (file only)

Exit codes: 0 success / nothing to do; 1 (--check only) changes would be made; 2 error (unsupported extension, parse failure, bad flags). On any error the file is left untouched. For a directory, 2 means at least one file errored — the rest were still processed.

Common uses

# Strip every comment from one file, in place
rm-comments src/main.rs

# Clean a whole project (respects .gitignore, skips hidden dirs)
rm-comments src/

# Preview without writing — CI/pre-commit friendly (exit 1 if anything would change)
rm-comments --check src/

# Remove EVERYTHING, including docs, directives, and markers
rm-comments --strip-doc-comments --strip-directives --strip-markers src/lib.rs

# Only touch the region you just edited
rm-comments --lines 40-80 src/handler.rs

# Pipe through a formatter without touching disk
rm-comments --stdin --lang rust < in.rs > out.rs

# Surgical removal: enumerate, pick ids, remove exactly those
rm-comments --list src/main.rs                 # -> JSON with an id per comment
rm-comments --apply 2,5,7 src/main.rs          # remove ids 2, 5, 7 only

Highlights

  • Safety — files that fail to parse are never modified; writes are atomic; line endings, shebang lines, and all non-comment content are preserved exactly. Running the tool twice produces the same result as running it once.
  • Selective removal — a bare run removes only plain narration comments. Doc comments, directives (eslint-disable, # noqa, //go:generate, …), and task markers (TODO, FIXME, HACK, XXX, BUG) are all kept unless you opt into removing them with --strip-doc-comments / --strip-directives / --strip-markers. User-defined --keep patterns and --lines scoping add further control.
  • LLM integration — this repo also ships a plugin whose skill (SKILL.md) applies a defined policy: comments that explain rationale or constraints are kept, comments that narrate what the code already expresses are removed.
  • Automation support — JSON enumeration of every comment, removal by id, line-range scoping, and a dry-run mode with conventional exit codes for CI and pre-commit use.

Safety guarantees

  • Files that don't parse cleanly, or have an unknown extension, are never modified.
  • Writes are atomic (temp file + rename) — a crash can't leave a truncated file.
  • Line endings (LF/CRLF), trailing-newline presence, and a #! shebang on line 1 are preserved. Idempotent: running twice = running once.
  • Everything that isn't a comment survives byte-for-byte, apart from deliberate whitespace cleanup: full-line comments are removed including their newline; trailing comments are removed along with the gap before them; blank-line runs around removals collapse to at most one blank line. The whole policy lives in one function (rebuild() in src/lib.rs).
  • Python docstrings are string expression statements in the grammar — they are correctly left in place. Only # comments are removed in Python files. By design, not a bug.
  • Doc comments (Rust //////!, JSDoc/Javadoc /** */, Doxygen /*!), directives, and task markers are kept by default — a bare run can't silently delete a /// doc or a // TODO. Pass --strip-doc-comments / --strip-directives / --strip-markers to remove a category.

Supported languages

For the authoritative list, see the LANGUAGES registry in src/languages.rs — every supported language, its file extensions, and grammar live there. Language is detected from the file extension (case-insensitive).

Adding a language

  1. cargo add tree-sitter-<lang>

  2. Add one entry to LANGUAGES in src/languages.rs:

    Lang {
        name: "kotlin",
        extensions: &["kt", "kts"],
        language: || tree_sitter_kotlin::LANGUAGE.into(),
        comment_kinds: &["comment"], // check the grammar's node-types.json
    },
  3. Add tests/fixtures/<name>/input.<ext> and expected.<ext> — the golden test picks them up automatically (and fails if the fixture pair is missing).

Comment node-kind names differ per grammar — verify against the grammar's node-types.json (most use "comment"; Rust and Java use "line_comment" + "block_comment").

Zed editor integration

rm-comments ships as a command in Zed via a task:

rm-comments install-zed-task

This adds a rm-comments task (pointing at the binary's own absolute path) to ~/.config/zed/tasks.json — creating the file, or splicing into an existing one while preserving your comments and trailing commas (a backup is written first; if the file looks too unusual to edit safely, it prints the snippet for you to paste instead). Idempotent.

Then in Zed: cmd-shift-ptask: spawnrm-comments. The task saves the focused buffer first ("save": "current"), strips the file on disk, and Zed reloads it. For a one-press keybinding, add zed/keymap.json to ~/.config/zed/keymap.json (cmd-alt-/ by default). Manual task setup: zed/tasks.json.

About

Safely and quickly strip unwanted comments from source files.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages