injm 0.6.0

A CLI tool that injects content into marked regions in source files.
injm-0.6.0 is not a library.

injm

A CLI tool that injects content into marked regions in source files.

Table of Contents

Installation

Cargo

cargo install injm

Nix

nix profile install github:Fovir-GitHub/injm

Download Binary

Download the latest binary for your platform from GitHub Releases.

Usage

injm uses subcommands. The main one is inject:

Basic Injection

Mark a region in your source file with injm begin and injm end comments:

dest.rs

fn main() {
    // injm begin
    // injm end
}

Then pipe content into injm:

echo -n 'println!("Hello, world!")' | injm inject --output dest.rs

Result:

dest.rs

fn main() {
    // injm begin
println!("Hello, world!");
    // injm end
}

Running injm inject again will replace the content between the markers:

cat src.txt | injm inject --output dest.rs

Inject into a Specific Region

Give a region an output ID with >id, then target it with --id:

dest.rs

fn main() {
    // injm begin >greeting
    // injm end

    // injm begin >farewell
    // injm end
}

Inject into a specific region:

echo -n 'println!("Hello!")' | injm inject --output dest.rs --id greeting

Inject into multiple regions at once:

echo -n 'println!("Hello!")' | injm inject --output dest.rs --id greeting --id farewell

If --id is not specified, only regions without an ID are injected; regions with a >id are left untouched.

Sync Between Files

Instead of piping from stdin, copy content between files with --input. Mark the source region with <id (the content to read) and the destination region with >id (where it goes):

src.rs

fn main() {
    // injm begin <hello
    println!("Hello, world!");
    // injm end
}

dest.rs

fn main() {
    // injm begin >hello
    // injm end
}

Then sync:

injm inject --input src.rs --output dest.rs

dest.rs becomes:

fn main() {
    // injm begin >hello
    println!("Hello, world!");
    // injm end
}

A region may read from several sources by listing multiple <id markers. If a >id in the output has no matching <id in the input, injm reports the missing ID and exits with an error.

Multiple Files and Globs

--input and --output accept multiple values and glob patterns:

# Multiple explicit files
injm inject --input src1.rs src2.rs --output dest.rs

# Sync to multiple outputs
injm inject --input src.rs --output out1.rs out2.rs

# Glob patterns
injm inject --input "src/**/*.rs" --output "docs/"

# Multiple globs
injm inject --input "mod_a/**/*.rs" "mod_b/**/*.rs" --output dest.rs

List Markers

Preview all marker regions across files:

injm list src/

Output:

+-------------+----------+--------+-------+
| File        | ID       | Type   | Lines |
+-------------+----------+--------+-------+
| src/main.rs | hello    | output | 6-7   |
+-------------+----------+--------+-------+
| src/main.rs | hello    | input  | 23-24 |
+-------------+----------+--------+-------+
| src/cli.rs  | greeting | input  | 1-2   |
+-------------+----------+--------+-------+

JSON output:

injm list src/ --format json

Accepts positional arguments (files, globs, or directories). Falls back to current directory when no argument is given.

Dry Run

Preview the result without writing to the file:

cat src.txt | injm inject --output dest.rs --dry-run

To see a unified diff of what would change instead of the full file, add --diff:

cat src.txt | injm inject --output dest.rs --dry-run --diff

Check

Verify that all output blocks (>id) contain the same content as their matching input blocks (<id):

injm check src/main.rs

If all blocks are synchronized, injm check exits 0 and prints:

all marker blocks are synchronized

If any are out of sync, it exits non-zero and lists each mismatch:

src/main.rs:12-14: output block `hello` is out of sync

To see a unified diff of what each out-of-sync block should contain, use --diff:

injm check src/main.rs --diff

Accepts files, globs, or directories as arguments. Falls back to current directory when no argument is provided.

Supported Languages

injm uses tree-sitter to parse source files, so markers are detected from actual comment nodes — not from string literals or other non-comment content.

Supports any language recognized by tree-sitter-language-pack, including:

  • Rust, C, C++
  • Python, Ruby
  • JavaScript, TypeScript
  • Go, Java
  • And 300+ more

Roadmap

See ROADMAP.md.

License

MIT

Acknowledgement

  • clap-rs/clap: A full featured, fast Command Line Argument Parser for Rust.
  • rust-lang/glob: Support for matching file paths against Unix shell style patterns.
  • serde-rs/serde: Serialization framework for Rust.
  • xberg-io/tree-sitter-language-pack: Comprehensive tree-sitter grammar compilation with polyglot bindings — Rust, Python, Node.js, Go, Java, Ruby, Elixir, PHP, C#, WASM, Dart, Kotlin-Android, Swift, Zig, and CLI. 306+ languages.
  • zhiburt/tabled: An easy to use library for pretty print tables of Rust structs and enums.