Skip to main content

toggle

A Rust CLI for toggling comment blocks in source code. Comment / uncomment line ranges, named sections, or grouped variants across one or many files — deterministic, atomic, language-aware.

Install

cargo install --path .
# or, from crates.io:
cargo install togl

Pre-built binaries via Homebrew are not yet published; see the Distribution section.

Quick start

# Toggle a line range in a Python file
toggle -l 10:20 main.py

# Toggle a named section across all matching files
toggle -S featureXYZ src/

# Force a section commented across a tree
toggle -S debug --force on -R src/

# Discover what sections exist in a tree
toggle --scan -R src/

Subcommands

Every operation is also available as a subcommand that exposes only the flags relevant to it. The subcommands are equivalent to the flat flags below (they run through the same engine), but are easier to discover and harder to misuse:

Subcommand Flat-flag equivalent
toggle <paths> -S id toggle <paths> -S id
toggle scan -R src/ toggle --scan -R src/
toggle check -R src/ toggle --scan --check -R src/
toggle list src/ toggle --list-sections src/
toggle insert main.py -S id -l 10:20 toggle --insert -S id -l 10:20 main.py
toggle remove main.py -S id toggle --remove -S id main.py

Run toggle <subcommand> --help to see its scoped flags. The flat-flag form still works and is supported, but is deprecated in favor of the subcommands.

Section markers

Wrap any block in a paired marker comment that the tool can find:

# toggle:start ID=featureX desc="Optional description"
print("guarded code")
# toggle:end ID=featureX

The single-line comment style is inferred from the file extension; override with --comment-style "//" (single) or --comment-style "//" "/*" "*/" (with multi-line delimiters).

Section variants (group:variant)

Use a : in the ID to mark variants of the same group. The CLI then knows how to swap, activate, or fan-out across them.

# toggle:start ID=db:sqlite
import sqlite3
# toggle:end ID=db:sqlite

# toggle:start ID=db:postgres
# import psycopg2
# toggle:end ID=db:postgres
Command Behavior
toggle -S db file.py Pair flip — swap active and commented variants (errors on 3+ variants without a qualifier)
toggle -S db:postgres file.py Activate — uncomment db:postgres, comment every other db:*
toggle -S db --force on file.py Force all — comment every variant in db
toggle -S db --pair file.py Guard — fail before any write if db does not have exactly 2 variants

Inserting a section

Wrap an existing line range in marker comments without commenting the body:

# Wrap lines 10–20 of main.py in an ID=featureX marker pair
toggle --insert -S featureX -l 10:20 main.py

# With a description
toggle --insert -S featureX -l 10:20 --desc "new feature" main.py

--insert operates on a single file and leaves the body uncommented. Run toggle -S featureX main.py afterward to comment the block.

Scan & check

# Per-file table with a TYPE column (solo / pair / group)
toggle --scan src/app.py

# Recursive summary, one row per group
toggle --scan -R src/

# Detailed view of one group: file refs + state per variant
toggle --scan -S db -R src/

# Validate without modifying: unclosed markers, duplicate IDs, cross-file gaps
toggle --scan --check -R src/

# Same, but only flag groups that should be pairs
toggle --scan --check --pair -R src/

# Machine-readable nested JSON
toggle --scan -R src/ --json

--check exits non-zero on any error finding (unclosed markers, duplicate IDs); warnings (variant gaps, pair-count mismatches) do not fail the run.

Filter mode (stdin → stdout)

The writer operations (toggle, insert, remove) can read from stdin and write the transformed result to stdout, leaving any file untouched — so toggle composes in a pipeline. Use a - path, or the --stdin / --stdout aliases:

# stdin → stdout: read stdin, write the result to stdout
cat main.py | toggle - -S featureX

# Equivalent spellings for stdin → stdout
toggle --stdin  -S featureX < main.py
toggle --stdout -S featureX < main.py

# file → stdout: transform a real file, print the result, leave the file on disk
# untouched (the prettier / clang-format model; great for editor integration).
toggle main.py --stdout -S featureX

# Works with the subcommands too
toggle remove --stdin -S featureX < main.py
toggle insert main.py --stdout -S featureX -l 10:20 > wrapped.py

With file --stdout, the comment style is resolved from the file's real extension. Piped (stdin) input has no extension, so it defaults to # (Python); pass --comment-style for other languages. Filter mode is always a single stream to stdout and never modifies a file, so it does not accept multiple files, directories, --json, --atomic, --backup, --dry-run, --interactive, or -R.

Atomic multi-file mode

# All files succeed or none are modified — backups created by default
toggle -S db:postgres --atomic -R src/

# Recover from an interrupted atomic run
toggle --recover            # rolls back
toggle --recover --recover-forward   # completes the commit

Distribution

  • From source: cargo install --path .
  • Shell completions: toggle --completions bash > /etc/bash_completion.d/toggle (also zsh, fish, powershell, elvish)
  • Man page: toggle --man > toggle.1 && man ./toggle.1
  • crates.io: togl — installs both toggle and togl binaries (same behavior under either name).
  • Homebrew: not yet published.

Reference

The remainder of this README is the original design spec, retained for historical context. CLI semantics in the spec match what's implemented unless called out above.

1. Overview

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

  1. 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.
  2. 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.
  3. Configurable comment styles: Auto-detect comment style by file extension or override with custom settings.
  4. Extendable: Allow a .toggleConfig file to hold global or per-language comment preferences.

2. Command-Line Interface (CLI)

2.1 Basic Command Syntax

toggle [OPTIONS] <file_or_directory_paths>...

2.2 Primary Flags & Arguments

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

2.3 Behavior Examples

  1. 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).
  2. Line Range to End

    toggle --line 30 --to-end MyClass.java
    
    • Auto-detects .java → uses // or /*...*/.
    • Comments out from line 30 to EOF.
  3. Section-Based Toggle

    toggle --section signupFlow --force on src/
    
    • Recursively scans src/ to find any sections labeled signupFlow.
    • Forces them all to become commented (on).
  4. 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 */.
  5. Multiple Toggles in One Command

    toggle --line 10:20 --section adminUI --force off module.ts
    
    • Toggles lines 10–20 and a named section adminUI in module.ts.
    • Forces off any commented region that is identified by adminUI.

3. Configuration File (.toggleConfig)

3.1 Purpose

  • Defines default behavior per file extension or globally.
  • Acts as the fallback if command-line arguments are not specified.

3.2 Format

[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:

  • global section sets the baseline.
  • Each [language.xxx] overrides settings for .xxx files.
  • If no extension is recognized, the program either throws an error or uses global defaults.

4. Section Markers in Source Files

4.1 Marker Convention

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=featureX

Or for Python:

# toggle:start ID=featureX desc="Enable the new feature"
print("New feature code here...")
# toggle:end ID=featureX

Proposed Format:

[toggle:start ID=<identifier> desc="<description>"]
...
[toggle:end ID=<identifier>]
  • ID is mandatory.
  • desc is 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)

4.2 Behavior

  • 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 on nor --force off is set, toggle inverts the current state.
  • Global Toggle: The tool can scan multiple files (via -R or listing files) and apply toggles to all occurrences of an ID.

5. Implementation Outline (Rust)

  1. Argument Parsing

    • Use a crate like Clap or StructOpt for robust CLI handling.
    • Collect line toggles (Vec<String> for <start_line>:<end_line>, etc.), sections, force states, and mode overrides.
  2. Configuration Handling

    • On startup, attempt to load .toggleConfig (or alternative path if --config is specified).
    • Parse with a TOML library (e.g., toml).
    • Merge config values with command-line overrides.
  3. File Scanner

    • If user inputs directories and -R is set, recursively walk the directory using walkdir.
    • Filter files by extension or by presence of toggle markers.
  4. 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 .toggleConfig contains [language.xyz] that matches extension, use those defaults unless overridden.
  5. 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=... and toggle:end ID=....
      • Determine if the block is currently commented or not.
      • Apply on/off or invert logic.
  6. 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.
    • Keep track of lines that are already partially or fully commented to avoid double-commenting.
  7. Output & Write-Back

    • After toggling, write the modified buffer back to the file (unless --dry-run is set).
    • If --dry-run, print a summary of changes.
  8. 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).

6. Example Use Case Scenarios

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 toggle in 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 off after tests complete.

7. Error Handling & Logging

  1. Unknown Extension

    • If --mode auto and the file extension has no known mapping, error: “Cannot detect comment style for ‘.xyz’. Use --mode or .toggleConfig to specify.”
  2. Conflicting Options

    • If --mode single and --comment-style multi-line tokens are provided, prefer the explicit --comment-style or show a warning and proceed with single-line prepends.
  3. Invalid Ranges

    • If start_line > end_line, skip or warn.
    • If lines exceed file length, skip out-of-bound lines and log a warning.
  4. Section Mismatch

    • If toggle:start ID=foo is found but no matching toggle:end ID=foo, log a warning: “Unclosed section ID=foo in filename.”
  5. Verbose Logging

    • If -v, --verbose, show each line range or section ID processed and the new state.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

togl-0.5.2-py3-none-win_amd64.whl (2.2 MB view details)

Uploaded Python 3Windows x86-64

togl-0.5.2-py3-none-musllinux_1_2_x86_64.whl (2.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

togl-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

togl-0.5.2-py3-none-macosx_11_0_arm64.whl (2.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

togl-0.5.2-py3-none-macosx_10_12_x86_64.whl (2.5 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file togl-0.5.2-py3-none-win_amd64.whl.

File metadata

  • Download URL: togl-0.5.2-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.2 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for togl-0.5.2-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 5e28c6feab8a0912df1f0559b41bbf6ad5951bafd2869e04959cb6a382a03ef2
MD5 72ecb4441e799714f2568a09bd0d0c7d
BLAKE2b-256 e5b72bd3a11eac618134df1763c3708503f62d751038d908f21312caa6064a00

See more details on using hashes here.

File details

Details for the file togl-0.5.2-py3-none-musllinux_1_2_x86_64.whl.

File metadata

  • Download URL: togl-0.5.2-py3-none-musllinux_1_2_x86_64.whl
  • Upload date:
  • Size: 2.8 MB
  • Tags: Python 3, musllinux: musl 1.2+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for togl-0.5.2-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 43bc50e68d18f8b6e534afe9c1aac89aebfdafb8eb455dcc0a29774f8ec76bd4
MD5 c7df7012e5cf645fbde023d7bd103713
BLAKE2b-256 cf9d5a52a58ff4c390c2588955615aad4d922370ad85c41d3da019a849104157

See more details on using hashes here.

File details

Details for the file togl-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: togl-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 2.7 MB
  • Tags: Python 3, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for togl-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e041fdd351d16a39501ebf0dbdcf2a5d649b60671486a1a6cb28b1e066dc74c8
MD5 cc0adac3d45aaf4e2cd7f9ba1474e0b7
BLAKE2b-256 e1b34dd85c834f67f612ed77b8b3eba53d9da609036de3c92b962bc909bf0d8f

See more details on using hashes here.

File details

Details for the file togl-0.5.2-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: togl-0.5.2-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 2.4 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for togl-0.5.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c5a0755f9112ffa89c93b6faa1132fee22597fe4af1b36187388f9eafa141018
MD5 169ef6bf73185bb032e1671f5f81b48a
BLAKE2b-256 9a5ceb0557178ca3dcdea4dbf731c096a685d6002bafab01eba72636b655b132

See more details on using hashes here.

File details

Details for the file togl-0.5.2-py3-none-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: togl-0.5.2-py3-none-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: Python 3, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for togl-0.5.2-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 76f570e0352874d5b2d6bf09f1ec3df825cdb9c7951b6faee446d30c7f2c520a
MD5 668786a1497109c07e35fa174cc2a893
BLAKE2b-256 3f9b9295b06ddf9d4595b54049b8fc261f6f31fa409eabe3dc131ef337c5a52d

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.2 This release

5 files

0.5.1

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page