A Rust-based CLI and library for toggling, adding, removing, and updating code/comments across multiple languages, featuring flexible extension mappings and full configurability via file or command-line.
Below is a structured technical requirements document for a command-line tool called toggle. This tool enables toggling comment blocks in one or more files. The focus is on Rust implementation details, supported comment styles, and multi-file toggling. Each section is designed to capture your requirements in a clear, concise format.
Goal
Create a Rust-based CLI tool, toggle, that can:
- Comment or uncomment designated lines or blocks of text in code files.
- Detect and apply correct single-line or multi-line comment styles by file extension.
- Work off a configuration file (
.toggleConfig) or command-line arguments. - Identify labeled "sections" to toggle on or off across multiple files.
- Provide granular control (line-based, section-based, file-based, multi-file).
Core Objectives
- Line-based toggling: Support start/end line numbers, or a start line with a fixed number of lines, or a start line to the end of the file.
- Section-based toggling: Recognize in-file sections tagged with an ID (e.g.,
SECTION_ID=foo) and toggle all occurrences (on/off) across a codebase. - Configurable comment styles: Auto-detect comment style by file extension or override with custom settings.
- Extendable: Allow a
.toggleConfigfile to hold global or per-language comment preferences.
toggle [OPTIONS] <file_or_directory_paths>...
| Flag / Arg | Description | Example |
|---|---|---|
-l, --line (repeatable) |
Specify line-based toggles in the format <start_line>:<end_line> or <start_line>:+<count>. |
--line 10:20 or --line 15:+5 |
-S, --section (repeatable) |
Specify section ID(s) to toggle. | --section featureXYZ |
-f, --force [on|off] |
Force a toggle state for line-based or section-based operations. | --force on |
-m, --mode [auto|single|multi] |
Defines the comment mode. auto will use file extension to determine the style, single/multi overrides. |
--mode single |
-c, --comment-style |
Manually specify exact delimiters for single/multi-line comments (overrides auto detection). | --comment-style "//" "/*" "*/" |
--to-end |
If set, toggling continues from <start_line> to the end of the file. |
--line 50 --to-end |
--config <path> |
Points to a custom .toggleConfig file. Default is .toggleConfig in current directory if present. |
--config /path/to/altConfig |
-R, --recursive |
Recursively search directories for files that match the toggled sections or line references. | -R src/ |
-v, --verbose |
Show detailed logs (lines changed, files modified, etc.). | --verbose |
--dry-run |
Show which changes would be made, without altering files. | --dry-run --verbose |
-
Line Range Toggle
toggle --line 10:20 main.py
- Auto-detects
.py→ uses#for single-line comments. - Comments out lines 10 to 20 (or toggles them if already commented).
- Auto-detects
-
Line Range to End
toggle --line 30 --to-end MyClass.java
- Auto-detects
.java→ uses//or/*...*/. - Comments out from line 30 to EOF.
- Auto-detects
-
Section-Based Toggle
toggle --section signupFlow --force on src/
- Recursively scans
src/to find any sections labeledsignupFlow. - Forces them all to become commented (on).
- Recursively scans
-
Override Comment Style
toggle --mode multi --comment-style "//" "/*" "*/" --line 40:45 test.cc
- Forces multi-line mode but uses custom single-line prefix
//if needed. - The multi-line delimiters are explicitly
/*and*/.
- Forces multi-line mode but uses custom single-line prefix
-
Multiple Toggles in One Command
toggle --line 10:20 --section adminUI --force off module.ts
- Toggles lines 10–20 and a named section
adminUIinmodule.ts. - Forces off any commented region that is identified by
adminUI.
- Toggles lines 10–20 and a named section
- Defines default behavior per file extension or globally.
- Acts as the fallback if command-line arguments are not specified.
[global]
default_mode = "auto"
force_state = "none" # valid: on, off, none (i.e., invert if toggling)
single_line_delimiter = "//"
multi_line_delimiter_start = "/*"
multi_line_delimiter_end = "*/"
[language.python]
single_line_delimiter = "#"
multi_line_delimiter_start = "\"\"\""
multi_line_delimiter_end = "\"\"\""
[language.ruby]
single_line_delimiter = "#"
[language.java]
single_line_delimiter = "//"
multi_line_delimiter_start = "/*"
multi_line_delimiter_end = "*/"Notes:
globalsection sets the baseline.- Each
[language.xxx]overrides settings for.xxxfiles. - If no extension is recognized, the program either throws an error or uses
globaldefaults.
A standard marker might look like this (example for Java/JS/C-style):
// toggle:start ID=featureX desc="Enable the new feature"
System.out.println("New feature code here...");
// toggle:end ID=featureXOr for Python:
# toggle:start ID=featureX desc="Enable the new feature"
print("New feature code here...")
# toggle:end ID=featureXProposed Format:
[toggle:start ID=<identifier> desc="<description>"]
...
[toggle:end ID=<identifier>]
IDis mandatory.descis optional.- The line format must be recognizable by
toggle. For example:// toggle:start ID=featureX desc="..."# toggle:start ID=featureX desc="..."/* toggle:start ID=featureX desc="..." */(depending on language)
- Toggling ON: If the block is not commented, comment it out. If already commented, do nothing.
- Toggling OFF: If the block is commented, uncomment it. If already uncommented, do nothing.
- No Force: If neither
--force onnor--force offis set,toggleinverts the current state. - Global Toggle: The tool can scan multiple files (via
-Ror listing files) and apply toggles to all occurrences of anID.
-
Argument Parsing
-
Configuration Handling
- On startup, attempt to load
.toggleConfig(or alternative path if--configis specified). - Parse with a TOML library (e.g., toml).
- Merge config values with command-line overrides.
- On startup, attempt to load
-
File Scanner
- If user inputs directories and
-Ris set, recursively walk the directory using walkdir. - Filter files by extension or by presence of
togglemarkers.
- If user inputs directories and
-
Comment Style Determination
- If
--mode auto, map extension → comment style. If not found, throw an error. - If
--comment-style ...is passed, override the style. - If
.toggleConfigcontains[language.xyz]that matches extension, use those defaults unless overridden.
- If
-
Parsing the File
- For each file, read line by line into a buffer (e.g.,
Vec<String>). - For line-based toggles:
- Identify the relevant range(s).
- Comment or uncomment accordingly.
- For section-based toggles:
- Detect lines that match
toggle:start ID=...andtoggle:end ID=.... - Determine if the block is currently commented or not.
- Apply on/off or invert logic.
- Detect lines that match
- For each file, read line by line into a buffer (e.g.,
-
Commenting / Uncommenting Logic
- Single-line approach (e.g.,
#,//): Prepend or remove the token from each line. - Multi-line approach (e.g.,
/* ... */):- Insert
/*at the first line,*/at the last line (or for partial lines, handle carefully). - Alternatively, comment each line singly if that's simpler for toggling.
- Insert
- Keep track of lines that are already partially or fully commented to avoid double-commenting.
- Single-line approach (e.g.,
-
Output & Write-Back
- After toggling, write the modified buffer back to the file (unless
--dry-runis set). - If
--dry-run, print a summary of changes.
- After toggling, write the modified buffer back to the file (unless
-
Edge Cases
- Overlapping toggles for the same lines or sections.
- Nested sections (some languages permit nested comment blocks).
- Files with unusual line endings (CRLF vs. LF).
- Extremely large files (consider streaming vs. loading entire file).
Scenario A: Toggling a Feature in Multiple Files
toggle --section featureX --force off -R src/
- Recursively looks for
toggle:start ID=featureX/toggle:end ID=featureX. - Forces it off. If some blocks were on, they get uncommented.
Scenario B: Automated Build Script
- Integrate
togglein a CI script to enable certain code blocks for a staging environment:toggle --section stagingFeature --force on path/to/config.yaml path/to/server.java
- Re-run with
--force offafter tests complete.
-
Unknown Extension
- If
--mode autoand the file extension has no known mapping, error: “Cannot detect comment style for ‘.xyz’. Use--modeor.toggleConfigto specify.”
- If
-
Conflicting Options
- If
--mode singleand--comment-stylemulti-line tokens are provided, prefer the explicit--comment-styleor show a warning and proceed with single-line prepends.
- If
-
Invalid Ranges
- If
start_line>end_line, skip or warn. - If lines exceed file length, skip out-of-bound lines and log a warning.
- If
-
Section Mismatch
- If
toggle:start ID=foois found but no matchingtoggle:end ID=foo, log a warning: “Unclosed section ID=foo in filename.”
- If
-
Verbose Logging
- If
-v, --verbose, show each line range or section ID processed and the new state.
- If