diff --git a/.taskmaster/docs/atomic-prd.txt b/.taskmaster/docs/atomic-prd.txt new file mode 100644 index 0000000..3061689 --- /dev/null +++ b/.taskmaster/docs/atomic-prd.txt @@ -0,0 +1,208 @@ +# Atomic Identifiers Feature - Product Requirements Document + +## Executive Summary +Add support for treating certain identifiers as "atomic" - indivisible units that should not have word boundaries detected during case transformations. This solves the problem where compound brand names like "DocSpring" or "GitHub" need to maintain their identity as single words in all case styles. + +## Problem Statement +Currently, when renaming identifiers like "DocSpring" or "GitHub", renamify detects word boundaries and generates variants like: +- `doc_spring` (snake_case) +- `doc-spring` (kebab-case) +- `DOC_SPRING` (SCREAMING_SNAKE_CASE) + +However, these brand names should be treated as single, indivisible units: +- `docspring` (snake_case) +- `docspring` (kebab-case) +- `DOCSPRING` (SCREAMING_SNAKE_CASE) +- `DocSpring` (PascalCase - the only time there is a word break) + +This is similar to Rails' `inflect.acronym` feature, but for compound words that aren't acronyms. + +## User Stories + +### Story 1: CLI User with Atomic Identifiers +As a developer renaming "HubGit" to "GitHub" in my codebase, +I want to specify that both names are atomic, +So that `hubgit_api` becomes `github_api` (not `git_hub_api`). + +### Story 2: Project with Persistent Atomic Configuration +As a team maintaining a project with brand names like "DocSpring", +I want to configure these as atomic in a config file, +So that all team members automatically get correct renaming behavior. + +### Story 3: VS Code Extension User +As a VS Code user, +I want checkboxes to mark search/replace terms as atomic, +So that I can control word boundary detection visually. + +### Story 4: Partial Atomic Matching +As a developer with "FormAPIController" in my code, +I want atomic "FormAPI" to match and replace the atomic portion correctly, +So that it becomes "DocSpringController" (not "DocSpringAPIController"). + +## Functional Requirements + +### 1. Core Atomic Detection +- When an identifier is marked as atomic, it should be treated as a single token +- Atomic identifiers should not have internal word boundaries detected +- The atomic property applies to the identifier wherever it appears (standalone or as part of larger identifiers) + +### 2. CLI Flags +- `--atomic` - Both search and replace are atomic +- `--atomic-search` - Only search term is atomic +- `--atomic-replace` - Only replace term is atomic +- `--no-atomic` - Override config, treat as normal +- `--no-atomic-search` - Override config for search term +- `--no-atomic-replace` - Override config for replace term +- Error if user specifies both `--atomic` and `--atomic-search`/`--atomic-replace` + +### 3. Configuration File +- Support `atomic = ["DocSpring", "GitHub", "GitHub"]` in `.renamify/config.toml` +- Config entries are case-insensitive matched (PascalCase in config matches all cases) +- Config auto-applies when matching identifiers are used +- CLI flags override config settings + +### 4. Variant Generation +For atomic identifier "DocSpring": +- Generate only: `DocSpring`, `docspring`, `DOCSPRING` +- Do NOT generate: `doc_spring`, `DOC_SPRING`, `doc-spring`, `docSpring` + +### 5. Compound Identifier Handling +When "FormAPI" is atomic: +- `FormAPIController` → `DocSpringController` +- `form_api_client` → `docspring_client` +- `FORMAPI_TOKEN` → `DOCSPRING_TOKEN` +- The atomic portion is preserved as a unit within larger identifiers + +### 6. VS Code Extension +- Add "Atomic" checkbox under Search field with tooltip +- Add "Atomic" checkbox under Replace field with tooltip +- Tooltips explain: "Treat as indivisible (no word boundaries)" +- Pre-check boxes if terms match config entries + +### 7. MCP Server +- Add `atomicSearch: boolean` parameter +- Add `atomicReplace: boolean` parameter +- Read and respect `.renamify/config.toml` atomic entries + +## Technical Requirements + +### 1. Case Model Refactoring +- Split `case_model.rs` into smaller modules (it's currently 1100 lines) +- Create `atomic.rs` module for atomic-specific logic +- Maintain backward compatibility + +### 2. Token Generation +- Modify `parse_to_tokens` to accept atomic hints +- When atomic, return single token regardless of internal capitals +- Preserve existing behavior when not atomic + +### 3. Variant Map Generation +- Update `generate_variant_map` to accept atomic flags +- Generate limited variants for atomic identifiers +- Handle mixed atomic/non-atomic scenarios + +### 4. Testing +- Unit tests for atomic token parsing +- Integration tests for compound identifiers +- End-to-end tests with real examples (DocSpring, GitHub) +- Performance tests to ensure no regression + +## Non-Functional Requirements + +### 1. Performance +- Atomic detection should not significantly impact scan performance +- Config file parsing should be cached + +### 2. Documentation +- Create "Atomic Identifiers" page in Features section +- Include examples of when to use atomic mode +- Document config file format + +### 3. Error Handling +- Clear error messages for conflicting flags +- Warn if atomic identifier contains delimiters + +## Acceptance Criteria + +### Test Case 1: Basic Atomic Renaming +```bash +renamify rename GitLab GitHub --atomic +``` +- `git_lab_api` → `GitHub_api` +- `GIT_LAB_TOKEN` → `GitHub_TOKEN` +- `GitLabController` → `GitHubController` + +### Test Case 2: Config File Auto-Application +`.renamify/config.toml`: +```toml +atomic = ["DocSpring"] +``` +```bash +renamify rename DocSpring Helper +``` +- `docspring_api` → `helper_api` (NOT `doc_spring_api` → `helper_api`) + +### Test Case 3: Partial Identifier Matching +```bash +renamify rename FormAPI DocSpring --atomic +``` +- `FormAPIController` → `DocSpringController` +- `useFormAPIHook` → `useDocSpringHook` + +### Test Case 4: Override Config +`.renamify/config.toml`: +```toml +atomic = ["DocSpring"] +``` +```bash +renamify rename DocSpring doc_spring --no-atomic-search +``` +- `DocSpring` → `doc_spring` (word boundary detected due to override) + +## Implementation Plan + +### Phase 1: Core Support (Week 1) +1. Refactor case_model.rs into modules +2. Implement atomic token parsing +3. Update variant generation +4. Add comprehensive tests + +### Phase 2: CLI Integration (Week 1) +1. Add CLI flags +2. Implement config file support +3. Wire up to plan operation +4. Add integration tests + +### Phase 3: UI Integration (Week 2) +1. Update VS Code extension +2. Update MCP server +3. Add tooltips and help text +4. End-to-end testing + +### Phase 4: Documentation (Week 2) +1. Create atomic identifiers documentation +2. Update existing docs with atomic examples +3. Add to README and help text + +## Success Metrics +- All test cases pass +- No performance regression (scan time within 5% of baseline) +- User feedback positive on solving word boundary issues +- Documentation clear (no support questions about basic usage) + +## Risks and Mitigations + +### Risk 1: Breaking Changes +**Mitigation**: Atomic mode is opt-in, existing behavior unchanged by default + +### Risk 2: Performance Impact +**Mitigation**: Early detection during parsing, benchmark before/after + +### Risk 3: User Confusion +**Mitigation**: Clear documentation, intuitive naming ("atomic"), helpful tooltips + +## Future Enhancements +- Support for regex patterns in atomic config +- Auto-detection of likely atomic identifiers based on casing patterns +- Project-specific dictionaries of atomic terms +- Integration with language-specific naming conventions diff --git a/CLAUDE.md b/CLAUDE.md index 06f0dd4..88a7714 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -136,6 +136,11 @@ Exit codes: - append only with checksums and revert info +`.renamify/config.toml` + +- Project configuration including atomic identifiers +- `atomic = ["DocSpring", "GitHub", "GitHub"]` - identifiers treated as indivisible units + ## Search and plan algorithm 1. Detect input case of `` and `` diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 469e8f2..7ff5cf6 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -63,6 +63,10 @@ export default defineConfig({ label: 'Resolving Case Ambiguity', slug: 'features/ambiguity-resolution', }, + { + label: 'Atomic Identifiers', + slug: 'features/atomic-identifiers', + }, ], }, { diff --git a/docs/src/content/docs/commands/plan.mdx b/docs/src/content/docs/commands/plan.mdx index 4516fb4..d43e3d7 100644 --- a/docs/src/content/docs/commands/plan.mdx +++ b/docs/src/content/docs/commands/plan.mdx @@ -58,6 +58,18 @@ renamify plan [PATHS]... [OPTIONS] - `--exclude-acronyms ` - Exclude specific acronyms from detection - `--only-acronyms ` - Only use these acronyms, ignore defaults +### Atomic Mode + +"Atomic" means treating a search or replace identifier as a single unit, +not splitting it into separate components. E.g. GitHub → github, not git_hub + +- `--atomic` - Treat both search and replace terms as indivisible units +- `--atomic-search` - Only treat search term as atomic +- `--atomic-replace` - Only treat replace term as atomic +- `--no-atomic` - Disable atomic mode (override config) +- `--no-atomic-search` - Disable atomic for search term +- `--no-atomic-replace` - Disable atomic for replace term + ### Display Options - `--fixed-table-width` - Use fixed column widths in table output for consistent @@ -171,6 +183,19 @@ renamify plan old_name new_name src/ tests/ renamify plan old_name new_name --dry-run ``` +### Atomic Mode + +```bash +# Treat compound words as single units +renamify plan DocSpring FormAPI --atomic + +# Only search term is atomic +renamify plan DocSpring form_api --atomic-search + +# Only replace term is atomic +renamify plan doc_spring FormAPI --atomic-replace +``` + ### Excluding Lines by Pattern ```bash diff --git a/docs/src/content/docs/commands/rename.mdx b/docs/src/content/docs/commands/rename.mdx index 03d3f55..78a5476 100644 --- a/docs/src/content/docs/commands/rename.mdx +++ b/docs/src/content/docs/commands/rename.mdx @@ -67,6 +67,18 @@ renamify rename [PATHS]... [OPTIONS] - `--exclude-acronyms ` - Exclude specific acronyms from detection - `--only-acronyms ` - Only use these acronyms, ignore defaults +### Atomic Mode + +"Atomic" means treating a search or replace identifier as a single unit, +not splitting it into separate components. E.g. GitHub → github, not git_hub + +- `--atomic` - Treat both search and replace terms as indivisible units +- `--atomic-search` - Only treat search term as atomic +- `--atomic-replace` - Only treat replace term as atomic +- `--no-atomic` - Disable atomic mode (override config) +- `--no-atomic-search` - Disable atomic for search term +- `--no-atomic-replace` - Disable atomic for replace term + ### Display Options - `--fixed-table-width` - Use fixed column widths in table output for consistent @@ -114,6 +126,16 @@ renamify rename oldApi newApi \ --exclude "**/*test*,node_modules/**" ``` +### Atomic Mode + +```bash +# Treat compound words as single units +renamify rename DocSpring FormAPI --atomic + +# Without --atomic, DocSpring would match doc_spring in snake_case +# With --atomic, DocSpring only matches docspring (as single unit) +``` + ### Case Style Control ```bash diff --git a/docs/src/content/docs/commands/search.mdx b/docs/src/content/docs/commands/search.mdx index 5cf80de..4258e40 100644 --- a/docs/src/content/docs/commands/search.mdx +++ b/docs/src/content/docs/commands/search.mdx @@ -54,6 +54,13 @@ Available styles: `snake`, `kebab`, `camel`, `pascal`, `screaming-snake`, - `--ignore-ambiguous` - Ignore mixed-case/ambiguous identifiers that don't match standard patterns +### Atomic Mode + +- `--atomic` - Treat the search term as an indivisible unit (no word boundaries) +- `--atomic-search` - Same as `--atomic` for search command +- `--no-atomic` - Disable atomic mode (override config) +- `--no-atomic-search` - Same as `--no-atomic` for search command + ### Output Control - `--preview ` - Preview format: `table`, `diff`, `matches`, `summary` @@ -132,6 +139,15 @@ renamify search myFunction --no-rename-paths renamify search cleanName --ignore-ambiguous ``` +### Atomic Search + +Search for compound words as single units: + +```bash +# DocSpring will match as a whole word, not doc_spring +renamify search DocSpring --atomic +``` + ### JSON Output for Processing ```bash diff --git a/docs/src/content/docs/features/atomic-identifiers.mdx b/docs/src/content/docs/features/atomic-identifiers.mdx new file mode 100644 index 0000000..2be820e --- /dev/null +++ b/docs/src/content/docs/features/atomic-identifiers.mdx @@ -0,0 +1,178 @@ +--- +title: Atomic Identifiers +description: Treat compound brand names and identifiers as indivisible units during case transformations +sidebar: + order: 7 +--- + +import { Tabs, TabItem, Code } from '@astrojs/starlight/components'; + +## Overview + +Atomic identifiers allow you to treat compound brand names and identifiers as indivisible units during case transformations. When an identifier is marked as atomic, Renamify preserves it as a single word without detecting internal word boundaries. + +This feature is essential for maintaining brand identity and preventing incorrect word splitting in compound names like "DocSpring" or "GitHub". + +## The Problem + +Without atomic mode, compound identifiers are split at word boundaries: + +```bash +# Without atomic mode +DocSpring → doc_spring (snake_case) +DocSpring → doc-spring (kebab-case) +DocSpring → DOC_SPRING (SCREAMING_SNAKE_CASE) +``` + +These transformations break the brand identity and can cause issues when the name should remain as a single unit. + +## The Solution + +With atomic mode, compound identifiers are preserved as single units: + +```bash +# With atomic mode +DocSpring → docspring (snake_case) +DocSpring → docspring (kebab-case) +DocSpring → DOCSPRING (SCREAMING_SNAKE_CASE) +DocSpring → DocSpring (PascalCase - preserved) +``` + +## Using Atomic Mode + +### Command Line Flags + +You can specify atomic mode using CLI flags: + + + + ```bash # Both search and replace terms are atomic renamify rename FormAPI + DocSpring --atomic + ``` + + + ```bash # Only search term is atomic renamify rename FormAPI Helper + --atomic-search + ``` + + + +```bash # Only replace term is atomic renamify rename OldName DocSpring +--atomic-replace +``` + + + + +### Configuration File + +You can configure commonly used atomic identifiers in `.renamify/config.toml`: + +```toml +# List of identifiers that should always be treated as atomic +atomic = ["DocSpring", "GitHub", "FormAPI"] +``` + +When configured identifiers are detected, they're automatically treated as atomic without needing CLI flags. + +### Overriding Configuration + +You can override the configuration file settings: + +```bash +# Override config to allow word boundaries +renamify rename DocSpring doc_spring --no-atomic-search + +# Override for search term only +renamify rename DocSpring Helper --no-atomic-search + +# Override for replace term only +renamify rename OldName DocSpring --no-atomic-replace +``` + +## Real-World Examples + +### Renaming a Brand Name + +When renaming "FormAPI" to "DocSpring" with atomic mode: + +```bash +renamify rename FormAPI DocSpring --atomic +``` + +Results: + +- `FormAPIController` → `DocSpringController` +- `formapi_client` → `docspring_client` +- `FORMAPI_TOKEN` → `DOCSPRING_TOKEN` +- `useFormAPIHook` → `useDocSpringHook` + +### Partial Matching + +Atomic identifiers are preserved even when they appear as part of larger identifiers: + +```bash +# GitHub is atomic +GitHubActions → GitHubActions (preserved in PascalCase) +github_api → github_api (preserved as single unit) +GITHUB_TOKEN → GITHUB_TOKEN (preserved as single unit) +``` + +## Case Transformation Behavior + +When an identifier is atomic, case transformations follow these rules: + +| Case Style | Non-Atomic | Atomic | +| -------------------- | ---------- | --------- | +| snake_case | doc_spring | docspring | +| kebab-case | doc-spring | docspring | +| camelCase | docSpring | docspring | +| PascalCase | DocSpring | DocSpring | +| SCREAMING_SNAKE_CASE | DOC_SPRING | DOCSPRING | +| Train-Case | Doc-Spring | Docspring | +| lowercase | docspring | docspring | +| UPPERCASE | DOCSPRING | DOCSPRING | + +## VS Code Extension + +The VS Code extension provides checkboxes for atomic mode: + +- **Atomic search**: Treat the search term as an indivisible unit +- **Atomic replace**: Treat the replace term as an indivisible unit + +These checkboxes include tooltips explaining their behavior and are automatically checked when terms match configured atomic identifiers. + +## Best Practices + +1. **Configure Common Brand Names**: Add frequently used brand names to your `.renamify/config.toml` +2. **Use for Compound Words**: Apply atomic mode to compound brand names and technical terms that should remain unified +3. **Consider Context**: Use atomic mode when the identifier's meaning depends on being a single unit +4. **Test First**: Use `--dry-run` to preview how atomic mode affects your renaming + +## Technical Details + +### How It Works + +1. **Token Parsing**: When atomic mode is enabled, the identifier bypasses normal word boundary detection +2. **Variant Generation**: Only case variants are generated, not word-separated variants +3. **Pattern Matching**: The atomic identifier is matched and replaced as a complete unit + +### Performance + +Atomic mode has minimal performance impact: + +- Detection happens during the parsing phase +- No additional scanning or regex operations required +- Config file is cached after first read + +## Limitations + +- Atomic mode applies to the entire identifier - you cannot make part of an identifier atomic +- Case-insensitive matching is used for configured atomic identifiers +- Atomic identifiers should not contain delimiters (underscores, hyphens, etc.) + +## See Also + +- [Case Transformations](/features/case-transformations) - Learn about supported case styles +- [Configuration](/cli/configuration) - Set up persistent atomic identifiers +- [CLI Reference](/cli/commands/rename) - Full command options diff --git a/docs/src/content/docs/mcp/tools.mdx b/docs/src/content/docs/mcp/tools.mdx index 50d5b00..810d11b 100644 --- a/docs/src/content/docs/mcp/tools.mdx +++ b/docs/src/content/docs/mcp/tools.mdx @@ -15,17 +15,18 @@ renaming. ### Parameters -| Parameter | Type | Required | Default | Description | -| ------------- | -------- | -------- | ----------- | -------------------------------------- | -| `search` | string | ✅ Yes | - | The identifier to search for | -| `paths` | string[] | No | Current dir | Paths to search (files or directories) | -| `includes` | string[] | No | All files | Glob patterns to include | -| `excludes` | string[] | No | None | Glob patterns to exclude | -| `styles` | string[] | No | All styles | Case styles to detect | -| `preview` | string | No | `summary` | Output format | -| `dryRun` | boolean | No | `false` | Preview without saving | -| `renameFiles` | boolean | No | `true` | Include file renames in search | -| `renameDirs` | boolean | No | `true` | Include directory renames in search | +| Parameter | Type | Required | Default | Description | +| -------------- | -------- | -------- | ----------- | -------------------------------------- | +| `search` | string | ✅ Yes | - | The identifier to search for | +| `paths` | string[] | No | Current dir | Paths to search (files or directories) | +| `includes` | string[] | No | All files | Glob patterns to include | +| `excludes` | string[] | No | None | Glob patterns to exclude | +| `styles` | string[] | No | All styles | Case styles to detect | +| `preview` | string | No | `summary` | Output format | +| `dryRun` | boolean | No | `false` | Preview without saving | +| `renameFiles` | boolean | No | `true` | Include file renames in search | +| `renameDirs` | boolean | No | `true` | Include directory renames in search | +| `atomicSearch` | boolean | No | `false` | Treat search term as indivisible unit | ### Example @@ -56,18 +57,20 @@ your identifiers. ### Parameters -| Parameter | Type | Required | Default | Description | -| ------------- | -------- | -------- | ----------- | -------------------------------------- | -| `old` | string | ✅ Yes | - | The identifier to replace | -| `new` | string | ✅ Yes | - | The new identifier | -| `paths` | string[] | No | Current dir | Paths to search (files or directories) | -| `includes` | string[] | No | All files | Glob patterns to include | -| `excludes` | string[] | No | None | Glob patterns to exclude | -| `styles` | string[] | No | All styles | Case styles to detect | -| `preview` | string | No | `summary` | Output format | -| `dryRun` | boolean | No | `false` | Preview without saving | -| `renameFiles` | boolean | No | `true` | Rename matching files | -| `renameDirs` | boolean | No | `true` | Rename matching directories | +| Parameter | Type | Required | Default | Description | +| --------------- | -------- | -------- | ----------- | -------------------------------------- | +| `old` | string | ✅ Yes | - | The identifier to replace | +| `new` | string | ✅ Yes | - | The new identifier | +| `paths` | string[] | No | Current dir | Paths to search (files or directories) | +| `includes` | string[] | No | All files | Glob patterns to include | +| `excludes` | string[] | No | None | Glob patterns to exclude | +| `styles` | string[] | No | All styles | Case styles to detect | +| `preview` | string | No | `summary` | Output format | +| `dryRun` | boolean | No | `false` | Preview without saving | +| `renameFiles` | boolean | No | `true` | Rename matching files | +| `renameDirs` | boolean | No | `true` | Rename matching directories | +| `atomicSearch` | boolean | No | `false` | Treat search term as indivisible unit | +| `atomicReplace` | boolean | No | `false` | Treat replace term as indivisible unit | ### Case Styles @@ -104,6 +107,21 @@ Arguments: { } ``` +### Atomic Mode Example + +``` +Tool: renamify_plan +Arguments: { + "old": "DocSpring", + "new": "FormAPI", + "atomicSearch": true, + "atomicReplace": true, + "preview": "summary" +} +``` + +With atomic mode, compound words like "DocSpring" are treated as single units, preventing unwanted word boundary detection (e.g., `doc_spring`). + ### Response Example ``` @@ -306,7 +324,7 @@ Last Applied: System: Renamify Version: 1.2.0 - Config: .renamify/config.json found + Config: .renamify/config.toml found History Entries: 47 ``` @@ -363,16 +381,18 @@ Perform case-aware renaming in a single step (combines plan + apply). ### Parameters -| Parameter | Type | Required | Default | Description | -| --------------- | -------- | -------- | ----------- | ------------------------- | -| `old` | string | ✅ Yes | - | The identifier to replace | -| `new` | string | ✅ Yes | - | The new identifier | -| `paths` | string[] | No | Current dir | Paths to search | -| `dryRun` | boolean | No | `false` | Preview without applying | -| `preview` | string | No | `summary` | Preview format | -| `excludeStyles` | string[] | No | None | Case styles to exclude | -| `includeStyles` | string[] | No | None | Additional case styles | -| `onlyStyles` | string[] | No | None | Use only these styles | +| Parameter | Type | Required | Default | Description | +| --------------- | -------- | -------- | ----------- | --------------------------------- | +| `old` | string | ✅ Yes | - | The identifier to replace | +| `new` | string | ✅ Yes | - | The new identifier | +| `paths` | string[] | No | Current dir | Paths to search | +| `dryRun` | boolean | No | `false` | Preview without applying | +| `preview` | string | No | `summary` | Preview format | +| `excludeStyles` | string[] | No | None | Case styles to exclude | +| `includeStyles` | string[] | No | None | Additional case styles | +| `onlyStyles` | string[] | No | None | Use only these styles | +| `atomicSearch` | boolean | No | `false` | Treat search term as indivisible | +| `atomicReplace` | boolean | No | `false` | Treat replace term as indivisible | ### Example Usage diff --git a/renamify-cli/.gitignore b/renamify-cli/.gitignore new file mode 100644 index 0000000..b25bec5 --- /dev/null +++ b/renamify-cli/.gitignore @@ -0,0 +1,2 @@ +# Renamify workspace +.renamify/ diff --git a/renamify-cli/src/cli/args.rs b/renamify-cli/src/cli/args.rs index 1f3a742..3382ef8 100644 --- a/renamify-cli/src/cli/args.rs +++ b/renamify-cli/src/cli/args.rs @@ -121,6 +121,34 @@ pub struct AcronymArgs { pub only_acronyms: Vec, } +/// Atomic identifier arguments +#[derive(Args, Debug, Clone)] +pub struct AtomicArgs { + /// Treat both terms as atomic (single words). E.g. DocSpring becomes docspring in snake_case, not doc_spring + #[arg(long, conflicts_with_all = ["atomic_search", "atomic_replace"])] + pub atomic: bool, + + /// Treat search term as atomic (GitHub → github, not git_hub) + #[arg(long)] + pub atomic_search: bool, + + /// Treat replace term as atomic (GitHub → github, not git_hub) + #[arg(long)] + pub atomic_replace: bool, + + /// Override config: allow word boundary detection + #[arg(long, conflicts_with = "atomic")] + pub no_atomic: bool, + + /// Override config for search: allow word boundaries + #[arg(long, conflicts_with = "atomic_search")] + pub no_atomic_search: bool, + + /// Override config for replace: allow word boundaries + #[arg(long, conflicts_with = "atomic_replace")] + pub no_atomic_replace: bool, +} + #[derive(Subcommand, Debug)] pub enum Commands { /// Initialize renamify in the current repository @@ -258,6 +286,9 @@ pub enum Commands { #[command(flatten)] acronyms: AcronymArgs, + #[command(flatten)] + atomic: AtomicArgs, + /// Output format for machine consumption #[arg(long, value_enum, default_value = "summary")] output: OutputFormat, @@ -374,6 +405,9 @@ pub enum Commands { #[command(flatten)] acronyms: AcronymArgs, + #[command(flatten)] + atomic: AtomicArgs, + /// Output format for machine consumption #[arg(long, value_enum, default_value = "summary")] output: OutputFormat, diff --git a/renamify-cli/src/main.rs b/renamify-cli/src/main.rs index 966df36..0770e8f 100644 --- a/renamify-cli/src/main.rs +++ b/renamify-cli/src/main.rs @@ -75,6 +75,7 @@ fn main() { plan_out, dry_run, acronyms, + atomic, output, quiet, } => { @@ -111,6 +112,7 @@ fn main() { acronyms.include_acronyms, acronyms.exclude_acronyms, acronyms.only_acronyms, + atomic, output, quiet, false, // regex flag - not used in Plan command @@ -173,6 +175,14 @@ fn main() { acronyms.include_acronyms, acronyms.exclude_acronyms, acronyms.only_acronyms, + cli::args::AtomicArgs { + atomic: false, + atomic_search: false, + atomic_replace: false, + no_atomic: false, + no_atomic_search: false, + no_atomic_replace: false, + }, output, quiet, false, // regex flag - not used in Search command @@ -227,6 +237,7 @@ fn main() { no_rename_root, dry_run, acronyms, + atomic: _, // Not implemented in rename yet output, quiet, } => { diff --git a/renamify-cli/src/plan.rs b/renamify-cli/src/plan.rs index 36c5b45..89ede8f 100644 --- a/renamify-cli/src/plan.rs +++ b/renamify-cli/src/plan.rs @@ -2,7 +2,7 @@ use anyhow::Result; use renamify_core::{plan_operation, OutputFormatter, Style}; use std::path::PathBuf; -use crate::cli::{types::StyleArg, OutputFormat}; +use crate::cli::{args::AtomicArgs, types::StyleArg, OutputFormat}; use renamify_core::Preview; #[allow(clippy::too_many_arguments)] @@ -30,6 +30,7 @@ pub fn handle_plan( include_acronyms: Vec, exclude_acronyms: Vec, only_acronyms: Vec, + atomic: AtomicArgs, output: OutputFormat, quiet: bool, _regex: bool, // TODO: Implement regex mode @@ -52,6 +53,17 @@ pub fn handle_plan( let include_styles: Vec