-
Notifications
You must be signed in to change notification settings - Fork 0
atomic identifiers (e.g. GitHub => github instead of git_hub), fixed ambiguity resolution #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add --atomic, --atomic-search, --atomic-replace CLI flags - Support atomic identifiers in .renamify/config.toml - Treat atomic identifiers as indivisible units during case transformations - Add comprehensive tests for atomic mode - Update all existing tests to handle atomic_config parameter Examples: - DocSpring (atomic) → docspring in snake_case (not doc_spring) - FormAPIController → DocSpringController when FormAPI is atomic - FORMAPI_TOKEN → DOCSPRING_TOKEN preserving atomic boundaries
- Add atomicSearch and atomicReplace parameters to plan, search, and rename tools - Update TypeScript interfaces with atomic options - Pass atomic flags to CLI commands when specified - All existing tests pass
- Add atomicSearch and atomicReplace checkboxes with tooltips - Update types to include atomic options - Pass atomic flags to CLI commands when checked - UI checkboxes explain 'indivisible unit (no word boundaries)'
- Create comprehensive documentation page for atomic identifiers - Explain use cases, CLI flags, and configuration options - Include real-world examples and best practices - Add to sidebar navigation under Features section
- Added atomic mode checkboxes to VS Code extension on same line - Implemented CSS-based tooltips with clear examples (DocSpring → docspring) - Fixed tooltip positioning to avoid screen edge cutoffs - Added "more info" link for ambiguous identifiers documentation - All checkboxes now trigger search re-run when toggled - Checkbox states persist when webview is hidden/shown - Fixed test assertions to match correct atomic behavior - Updated documentation with proper MDX formatting The atomic feature now properly treats compound brand names as indivisible units during case transformations across CLI, MCP server, and VS Code extension. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Updated search, plan, and rename command docs with atomic flags - Added atomic parameters to MCP tool documentation - Added examples showing atomic mode usage - Documented both --atomic-search and --atomic-replace options Note: Testing revealed atomic mode is not fully working yet - produces FormApi instead of FormAPI. Implementation needs fixing. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Add exact match preservation to maintain user's exact casing (e.g., FormAPI stays FormAPI, not FormApi) - Only apply exact match when using default styles, not with --only-styles flag - Improve acronym boundary detection for compound words (e.g., APIClient → API + Client) - Handle consecutive acronyms correctly (e.g., HTTPSAPIClient → HTTPS + API + Client) - Add case consistency check to avoid false acronym matches (e.g., 'Cli' is not 'CLI') - Preserve known acronyms in PascalCase and camelCase outputs This ensures that compound brand names and technical terms with acronyms are preserved exactly as the user types them, while still generating appropriate variants for different case styles.
- Wire up ambiguity resolver in scanner.rs to actually use the extensive ambiguity resolution code - Fix ambiguity detection to be more precise: - PascalCase requires no separators (not just starting with uppercase) - Train-Case requires hyphens or proper Title/acronym segments - Title Case requires spaces (not just starting with uppercase) - ScreamingTrain requires hyphens (not just all uppercase) - Add integration tests for ambiguity resolution in Python and JavaScript contexts - Fix binary name preservation test to find correct line numbers - Add debug logging to language heuristics for troubleshooting - Ensure exact match preservation works for non-ambiguous mixed-case identifiers The key fix is that ambiguous identifiers (like 'api', 'API') now use context-aware resolution to determine the appropriate case style based on language-specific heuristics, while non-ambiguous identifiers (like 'OAuth', 'WeIrDCaSe') preserve exact user casing. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
When ambiguous identifiers like 'renamify' are found in contexts where language heuristics don't provide a clear style preference (like TOML package names), the resolver now uses the style of the replacement text as a hint. Key changes: - Pass original replacement text to ambiguity resolver (not the styled variant) - Calculate replacement possible styles once per file for performance - In default_fallback, find intersection of matched and replacement styles - If replacement is snake_case (awesome_file_renaming_tool), prefer that This fixes the e2e test where binary names were becoming camelCase instead of preserving the snake_case from the replacement string. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
|
Caution Review failedThe pull request is closed. WalkthroughAdds Atomic Identifiers feature across core, CLI, MCP, and VS Code: new atomic config, parsing, and variant generation; ambiguity resolver enhancements; scanner integration; CLI flags and wiring; MCP and VS Code options/UX; extensive documentation; tests added and updated; config gains atomic list. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as Renamify CLI
participant Core as renamify_core::plan_operation
participant Scan as Scanner
participant Amb as AmbiguityResolver
User->>CLI: plan --search S --replace R [--atomic*]
CLI->>Core: plan_operation(S, R, ..., atomic_config)
Core->>Scan: scan_repository_multi(..., atomic_config)
alt atomic_config present
Scan->>Scan: generate_variant_map_with_atomic(S, R)
else non-atomic
Scan->>Scan: generate_variant_map_with_acronyms(S, R)
end
loop For each match
alt ambiguous variant
Scan->>Amb: resolve_with_styles(matched, R, context, precomputed R styles)
Amb-->>Scan: ResolvedStyle
Scan->>Scan: restyle R tokens -> styled_replacement
else compound/exact
Scan->>Scan: use variant_map replacement
end
end
Scan-->>Core: Plan with matches
Core-->>CLI: PlanResult
CLI-->>User: Preview/JSON
sequenceDiagram
autonumber
actor Dev as VS Code User
participant UI as VS Code Webview
participant Ext as VS Code Extension
participant MCP as MCP Service
participant CLI as Renamify CLI
Dev->>UI: Toggle Atomic Search/Replace
UI->>Ext: postMessage{atomicSearch, atomicReplace}
Ext->>MCP: createPlan(options with atomic*)
MCP->>CLI: renamify plan --atomic-search/--atomic-replace
CLI-->>MCP: Plan JSON
MCP-->>Ext: Plan result
Ext-->>UI: Render plan
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (4)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Welcome to Codecov 🎉Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests. Thanks for integrating Codecov - We've got you covered ☂️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
renamify-core/tests/hyphenated_capitalized_test.rs (1)
45-45: Ensure plan files are written inside the temp dirUsing a bare "plan.json" risks writing to the process CWD if scan_repository doesn’t relocate paths. Safer to write into the test sandbox.
- plan_out: PathBuf::from("plan.json"), + plan_out: root.join("plan.json"),Also applies to: 155-155, 237-237, 313-313, 391-391
renamify-cli/src/replace.rs (1)
143-154: Avoid cloning Plan before apply; pass &mut plan directly.Cloning can be very expensive on large plans and discards any in-place updates made during apply.
Apply:
- let plan = if no_regex { + let mut plan = if no_regex { // Literal string replacement create_simple_plan(pattern, replacement, paths, &options, false)? } else { // Regex replacement - validate the pattern first Regex::new(pattern).with_context(|| format!("Invalid regex pattern: {}", pattern))?; // Create plan with regex replacement create_simple_plan(pattern, replacement, paths, &options, true)? }; @@ - apply_plan(&mut plan.clone(), &apply_options)?; + apply_plan(&mut plan, &apply_options)?;renamify-vscode/webview/src/webview.ts (1)
350-358: Keep openPreview in sync with search/apply (missing flags).openPreview doesn’t pass renamePaths/ignoreAmbiguous/atomic* so preview can diverge from search/apply results. Add the four booleans.
vscode.postMessage({ type: 'openPreview', search: searchTerm, replace: replaceTerm, include: includeInput.value, exclude: excludeInput.value, excludeMatchingLines: excludeLinesInput.value, - caseStyles: selectedStyles, + caseStyles: selectedStyles, + renamePaths: renamePathsCheckbox?.checked ?? false, + ignoreAmbiguous: ignoreAmbiguousCheckbox?.checked ?? false, + atomicSearch: atomicSearchCheckbox?.checked ?? false, + atomicReplace: atomicReplaceCheckbox?.checked ?? false, });renamify-cli/src/main.rs (1)
222-241: Reject unsupportedatomicflags inrename
renamesilently ignores the--atomic*flags (they’re destructured as_), which is confusing. Explicitly refuse them until support is implemented.In the
Commands::Renamearm inmain.rs, update:- atomic: _, // Not implemented in rename yet + atomic,and immediately after the match add:
if atomic.atomic || atomic.atomic_search || atomic.atomic_replace || atomic.no_atomic || atomic.no_atomic_search || atomic.no_atomic_replace { eprintln!("--atomic* flags are not yet supported in `rename`. Use `plan` + `apply` for now."); process::exit(2); }renamify-core/src/ambiguity/resolver.rs (2)
160-166: Potential UTF-8 panic: slicing with byte offsets on &strmatch_position is a byte offset. Using &line[..match_pos] panics on non–char-boundary indices.
- let preceding = if match_pos > 0 { - &line[..match_pos] - } else { - "" - }; + let preceding = line.get(..match_pos).unwrap_or("");Apply the same fix in try_cross_file_context.
Also applies to: 225-231
369-375: Don’t fall back to Style::Lower; it contradicts “never use lower/upper” policyLower/Upper destroy word boundaries. Return a safe style (e.g., Snake) instead.
- ResolvedStyle { - style: Style::Lower, - confidence: ResolutionConfidence::Low, - method: ResolutionMethod::DefaultFallback, - } + ResolvedStyle { + style: Style::Snake, + confidence: ResolutionConfidence::Low, + method: ResolutionMethod::DefaultFallback, + }renamify-core/src/scanner.rs (1)
570-591: Potential UTF-8 panic when building line_afterline_string[match_col..] can panic if match_col isn’t on a char boundary. Use get() and fall back safely.
- let line_after = - if match_col < line_string.len() && line_string[match_col..].starts_with(&content) { - let mut after_line = String::new(); - after_line.push_str(&line_string[..match_col]); - after_line.push_str(&replace); - after_line.push_str(&line_string[match_col + content.len()..]); - after_line - } else { + let line_after = if let Some(tail) = line_string.get(match_col..) { + if tail.starts_with(&content) { + let mut after_line = String::new(); + after_line.push_str(&line_string[..match_col]); + after_line.push_str(&replace); + after_line.push_str(&line_string[match_col + content.len()..]); + after_line + } else { + // Fallback: try to find the match in the line + if let Some(match_pos) = line_string.find(&content) { + let mut after_line = String::new(); + after_line.push_str(&line_string[..match_pos]); + after_line.push_str(&replace); + after_line.push_str(&line_string[match_pos + content.len()..]); + after_line + } else { + line_before.clone() + } + } + } else { // Fallback: try to find the match in the line if let Some(match_pos) = line_string.find(&content) { let mut after_line = String::new(); after_line.push_str(&line_string[..match_pos]); after_line.push_str(&replace); after_line.push_str(&line_string[match_pos + content.len()..]); after_line } else { // Could not find the match in the line - this shouldn't happen line_before.clone() } - }; + };
🧹 Nitpick comments (54)
renamify-cli/.gitignore (1)
1-2: Ignore entry looks good; consider adding project-wide ignore tooNice addition. Consider also adding the same pattern to the repo root .gitignore so user workspaces don’t accidentally commit .renamify when running the CLI from project roots outside renamify-cli.
renamify-cli/src/cli/args.rs (2)
289-291: Flag naming may confuse with Apply’s --atomicRename/Plan use --atomic for “atomic identifiers,” while Apply uses --atomic for “atomic apply.” Consider a more explicit long flag (e.g., --atomic-identifiers) or clarifying help text to reduce ambiguity.
- #[command(flatten)] - atomic: AtomicArgs, + #[command(flatten)] + atomic: AtomicArgs, // consider: rename long flag(s) to --atomic-identifiers/--no-atomic-identifiers
408-410: Parallels the Rename UX; consider Search parityPlan exposes atomic flags; Search does not. If you want preview-only flows to reflect atomic tokenization, expose AtomicArgs on Search too for consistency.
// In the Search subcommand fields: - #[command(flatten)] - acronyms: AcronymArgs, + #[command(flatten)] + acronyms: AcronymArgs, + #[command(flatten)] + atomic: AtomicArgs,renamify-vscode/media/style.css (1)
146-229: Add keyboard accessibility for tooltipsTooltips are hover-only. Add focus support so keyboard users can access them; also respect reduced motion.
.tooltip-wrapper:hover .tooltip-text { opacity: 1; visibility: visible; } +/* Keyboard accessibility */ +.tooltip-wrapper:focus-within .tooltip-text { + opacity: 1; + visibility: visible; +} + +@media (prefers-reduced-motion: reduce) { + .tooltip-text { + transition: none; + } +}Also ensure the trigger element in the HTML is focusable (e.g., button with aria-describedby).
docs/src/content/docs/mcp/tools.mdx (4)
18-29: Document atomicSearch behavior relative to config.tomlAdd a note that atomicSearch also auto-enables when the term matches an entry in .renamify/config.toml, and that an explicit false overrides config. This prevents confusion about precedence.
60-74: Clarify styles options parity with renamePlan uses styles, whereas Rename uses includeStyles/excludeStyles/onlyStyles. Add a one-line note linking these so users know how to achieve the same filtering in each tool.
110-124: Atomic Mode example: add exact-match preservation noteRecommend adding a sentence that exact-casing of matched text is preserved when atomicSearch/atomicReplace are enabled (e.g., DocSpring → FormAPI, docspring → formapi).
384-395: Disambiguate “atomic” (apply) vs “atomic identifiers”Elsewhere, “atomic” means transactional apply; here atomicSearch/atomicReplace refer to identifier indivisibility. Add an info callout to avoid conflation.
### Parameters @@ -| `atomicSearch` | boolean | No | `false` | Treat search term as indivisible | -| `atomicReplace` | boolean | No | `false` | Treat replace term as indivisible | +| `atomicSearch` | boolean | No | `false` | Treat search term as indivisible | +| `atomicReplace` | boolean | No | `false` | Treat replace term as indivisible | + +> Note: “atomicSearch/atomicReplace” (identifier indivisibility) is unrelated to the `atomic` flag in renamify_apply (transactional apply)..taskmaster/docs/atomic-prd.txt (1)
33-35: Grammar: add “to”“I want checkboxes to mark …”
- I want checkboxes to mark search/replace terms as atomic, + I want checkboxes to mark search/replace terms as atomic,renamify-core/src/ambiguity/mod.rs (2)
49-51: Comment and implementation mismatch for PascalComment says “has mixed case,” but implementation only checks starts uppercase and no separators. Align the comment to avoid confusion.
- // PascalCase: starts uppercase, has mixed case, no separators + // PascalCase: starts uppercase, no separators (mixed case not required)
91-93: Title detection may admit “Title 123”; confirm numeric policyIf numerics in Title segments should be allowed, keep; otherwise consider restricting to letters and spaces.
renamify-core/src/lib.rs (1)
15-15: Consider re-exporting AtomicConfig and helpers for API parityMost core modules re-export primary types/functions; do the same for atomic to simplify consumers.
pub mod atomic; +pub use atomic::{AtomicConfig /*, parse_atomic, to_atomic_style, generate_atomic_variants*/};renamify-core/tests/compound_word_test.rs (1)
40-41: DRY up PlanOptions initialization (atomic_config default)atomic_config: None is repeated in many tests. Introduce a small helper to reduce duplication and future drift.
+fn default_options() -> PlanOptions { + PlanOptions { + exclude_match: vec![], + exclude_matching_lines: None, + no_acronyms: false, + include_acronyms: vec![], + exclude_acronyms: vec![], + only_acronyms: vec![], + ignore_ambiguous: false, + atomic_config: None, + includes: vec![], + excludes: vec![], + respect_gitignore: false, + unrestricted_level: 0, + styles: None, + rename_files: false, + rename_dirs: false, + rename_root: false, + plan_out: PathBuf::from("plan.json"), + coerce_separators: renamify_core::scanner::CoercionMode::Auto, + } +}Optionally use struct update syntax in each test:
let mut options = default_options(); options.styles = Some(vec![renamify_core::Style::Pascal]);Also applies to: 127-128, 210-211, 297-298, 369-370, 429-430, 511-512, 689-690, 789-790, 892-893, 1017-1018, 1141-1142, 1268-1269
renamify-cli/src/replace.rs (1)
144-152: Name collision risk: ApplyOptions.atomic vs “Atomic Identifiers”.The boolean “atomic” here is about transactional apply, not Atomic Identifiers. Consider a brief comment to disambiguate for future readers.
let apply_options = renamify_core::ApplyOptions { create_backups: true, backup_dir: PathBuf::from(".renamify/backups"), - atomic: true, + atomic: true, // transactional apply (not related to Atomic Identifiers) commit: false, force: force_with_conflicts, skip_symlinks: false, log_file: None, };renamify-vscode/extension/src/cliService.ts (2)
432-434: Don’t skip version check when the search term is literally “version”.args.includes('version') can match a positional search term. Check the subcommand instead.
- if (!args.includes('version') && this.cliPath !== 'mocked-cli-path') { + if (args[0] !== 'version' && this.cliPath !== 'mocked-cli-path') { await this.checkVersionCompatibility(); }
411-413: Return type nullability mismatch.cliPath is string | null but getBinaryPath returns string | undefined. Coalesce to undefined (or change return type).
- public getBinaryPath(): string | undefined { - return this.cliPath; + public getBinaryPath(): string | undefined { + return this.cliPath ?? undefined; }renamify-cli/tests/cli_tests.rs (1)
98-101: Add a CLI end-to-end test for atomic mode
Include in renamify-cli/tests/cli_tests.rs a case that invokes the CLI with --atomic (or --atomic-search/--atomic-replace) and asserts atomic behavior (e.g. “GitHub → github”, not “git_hub”) to prevent regressions.renamify-vscode/extension/templates/webview.hbs (1)
93-118: Improve accessibility for atomic tooltips.Provide screen-reader context for the info icons.
- <span class="codicon codicon-info tooltip-icon"></span> + <span class="codicon codicon-info tooltip-icon" aria-label="Atomic search info" role="img"></span> … - <span class="codicon codicon-info tooltip-icon"></span> + <span class="codicon codicon-info tooltip-icon" aria-label="Atomic replace info" role="img"></span>renamify-core/tests/compound_position_test.rs (1)
36-37: Add at least one positive atomic-config test.Cover an atomic scenario (e.g., search GitHub, replace github) with atomic_config=Some(...) to lock desired behavior.
renamify-core/tests/replace_column_position_test.rs (1)
25-26: Ensure column math stays correct under atomic mode.Add a parallel case with atomic_config=Some(...) to assert that hunk.col remains 0-based and unchanged by atomic tokenization.
Also applies to: 92-93, 158-159
docs/src/content/docs/commands/plan.mdx (2)
61-69: Clarify atomic flag semantics and tighten wordingSuggest making precedence explicit and polishing phrasing for consistency.
Apply this diff:
-### Atomic Mode +### Atomic Mode -- `--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 +- `--atomic` - Treat both the search and replacement terms as indivisible units (overrides config) +- `--atomic-search` - Treat only the search term as atomic (overrides config) +- `--atomic-replace` - Treat only the replacement term as atomic (overrides config) +- `--no-atomic` - Disable atomic mode (overrides config) +- `--no-atomic-search` - Disable atomic for the search term (overrides config) +- `--no-atomic-replace` - Disable atomic for the replacement term (overrides config) + +Note: If both enabling and disabling flags are provided, the corresponding `--no-atomic*` flag wins.
183-195: Improve example wording; “identifiers” vs “words” and add clarityMinor wording to better reflect identifier semantics and set expectations.
Apply this diff:
-# Treat compound words as single units +# Treat compound identifiers as single units renamify plan DocSpring FormAPI --atomic -# Only search term is atomic +# Only the search term is atomic (replacement will follow normal style rules) renamify plan DocSpring form_api --atomic-search -# Only replace term is atomic +# Only the replacement term is atomic (search will follow normal style rules) renamify plan doc_spring FormAPI --atomic-replacerenamify-core/tests/train_case_literals_test.rs (1)
175-175: Reduce boilerplate in test option setup (optional)Consider a small helper/builder for
PlanOptionsin tests to avoid repeating unchanged defaults.For example, add a
tests/util.rswith a constructor that sets common defaults and accepts overrides.docs/src/content/docs/commands/search.mdx (2)
57-63: Tighten Atomic Mode descriptions and consistencySmall grammar/consistency pass and explicit precedence.
Apply this diff:
-### Atomic Mode +### 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 +- `--atomic` - Treat the search term as an indivisible unit (no splitting across separators; overrides config) +- `--atomic-search` - Same as `--atomic` for the search command (overrides config) +- `--no-atomic` - Disable atomic mode (overrides config) +- `--no-atomic-search` - Same as `--no-atomic` for the search command (overrides config)
142-149: Clarify what atomic search will not matchSpell out common near-misses to set expectations.
Apply this diff:
-# DocSpring will match as a whole word, not doc_spring -renamify search DocSpring --atomic +# DocSpring will match as a whole identifier (not "doc_spring" or "docspring") +renamify search DocSpring --atomicrenamify-core/src/ambiguity/language_heuristics.rs (1)
16-26: Debug visibility for files without/invalid extensionsBy computing
extensionwith?, we return early and emit no debug logs for extensionless or non-UTF-8 extensions. If you want visibility when debugging ambiguity, consider logging that case before returning.Apply this diff:
- let extension = file_path.extension()?.to_str()?; - let context = preceding_context.trim(); + let context = preceding_context.trim(); + let ext_opt = file_path.extension().and_then(|e| e.to_str()); + let extension = match ext_opt { + Some(ext) => ext, + None => { + if std::env::var("RENAMIFY_DEBUG_AMBIGUITY").is_ok() { + eprintln!("DEBUG LanguageHeuristics: unsupported or missing extension for {}", file_path.display()); + eprintln!(" preceding_context: {:?}", preceding_context); + eprintln!(" context (trimmed): {:?}", context); + eprintln!(" possible_styles: {:?}", possible_styles); + } + return None; + } + };renamify-mcp/src/index.ts (1)
149-153: Atomic flag for search: consider string→boolean coercionMCP callers sometimes send booleans as strings. Consider coercing to boolean to harden the schema.
- atomicSearch: z - .boolean() - .optional() + atomicSearch: z.preprocess( + (v) => (v === 'true' ? true : v === 'false' ? false : v), + z.boolean() + ).optional() .describe('Treat search term as atomic (indivisible unit)'),docs/src/content/docs/commands/rename.mdx (2)
70-77: Tighten phrasing for bullet list (minor grammar)Reword for parallel construction and clarity.
- - `--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 + - `--atomic` - Treat both search and replace terms as indivisible units + - `--atomic-search` - Treat only the search term as atomic + - `--atomic-replace` - Treat only the replace term as atomic + - `--no-atomic` - Disable atomic mode (overrides config) + - `--no-atomic-search` - Disable atomic mode for the search term + - `--no-atomic-replace` - Disable atomic mode for the replace term
126-135: Clarify replacement behavior in exampleAdd one line noting that atomic also affects how the replacement is rendered across styles.
# With --atomic, DocSpring only matches docspring (as single unit) +# And the replacement 'FormAPI' will render as 'formapi' in single-unit styles (no separators).renamify-core/tests/multiple_matches_per_line_test.rs (2)
124-128: Dot-path test: make assertions deterministic and isolate plan fileConsider asserting the exact expected count (5) and writing
plan_outinto the temp dir to avoid cross-test collisions.- std::fs::write( + std::fs::write( &test_file, "mkdir .awesometool\n\ cd .awesometool\n\ echo 'awesometool' > .awesometool/config\n\ rm -rf .awesometool\n", ) @@ - let plan = scan_repository(&root, "awesometool", "smart_search", &options).unwrap(); + let plan = scan_repository(&root, "awesometool", "smart_search", &options).unwrap(); @@ - assert!( - plan.stats.total_matches >= 5, - "Should find awesometool in regular text and .awesometool paths" - ); + assert_eq!( + plan.stats.total_matches, 5, + "Should find 5 occurrences (including dot-prefixed paths)" + ); @@ - assert!( - !dot_matches.is_empty(), - "Should find .awesometool occurrences" - ); + assert!( + dot_matches.len() >= 4, + "Should find .awesometool occurrences on mkdir/cd/path/rm lines" + );And for all tests in this file, prefer:
- plan_out: PathBuf::from("plan.json"), + plan_out: root.join("plan.json"),Also applies to: 152-158, 160-174
18-37: Reduce PlanOptions boilerplate in testsIntroduce a small helper to build
PlanOptionswith sensible defaults, overridden per test, to cut duplication.// tests/util.rs pub fn base_options(root: &Path) -> PlanOptions { PlanOptions { exclude_match: vec![], exclude_matching_lines: None, no_acronyms: false, include_acronyms: vec![], exclude_acronyms: vec![], only_acronyms: vec![], ignore_ambiguous: false, atomic_config: None, includes: vec![], excludes: vec![], respect_gitignore: false, unrestricted_level: 0, styles: None, rename_files: false, rename_dirs: false, rename_root: false, plan_out: root.join("plan.json"), coerce_separators: renamify_core::scanner::CoercionMode::Auto, } }renamify-core/tests/dot_directory_test.rs (2)
43-45: Write plan.json inside temp dirAvoid writing to CWD to prevent cross-test interference.
- plan_out: PathBuf::from("plan.json"), + plan_out: root.join("plan.json"),Also applies to: 140-142, 215-217, 268-270
47-60: Add debug logging of matched entries before asserting totals
To help diagnose occasional mismatches, print the full list of matches (e.g.println!("{:?}", plan.matches);) immediately before eachassert_eq!(plan.stats.total_matches, …);.renamify-mcp/src/renamify-service.ts (4)
29-30: Add brief docs for atomicSearch.A short JSDoc clarifying semantics (tokenization boundary rules, default) will help tool consumers.
Apply this diff:
ignoreAmbiguous?: boolean; - atomicSearch?: boolean; + /** Treat search term as an atomic identifier; only match whole atoms. */ + atomicSearch?: boolean;
44-46: Annotate atomic flags for clarity and future compatibility.Doc both options and note interaction with CLI flags.
ignoreAmbiguous?: boolean; - atomicSearch?: boolean; - atomicReplace?: boolean; + /** Search side is atomic; narrows matches to whole identifiers. */ + atomicSearch?: boolean; + /** Replacement side is atomic; preserves intended casing/boundaries. */ + atomicReplace?: boolean;
254-265: Good helper extraction; consider reuse in rename for consistency.Reuse these helpers in rename() to avoid flag drift.
private addAtomicReplaceArg(args: string[], atomicReplace?: boolean): void { if (atomicReplace) { args.push('--atomic-replace'); } }
485-492: Deduplicate flag assembly in rename().Use the same helpers to keep behavior aligned with plan/search.
- // Add atomic flags - if (options.atomicSearch) { - args.push('--atomic-search'); - } - if (options.atomicReplace) { - args.push('--atomic-replace'); - } + // Add atomic flags + this.addAtomicSearchArg(args, options.atomicSearch); + this.addAtomicReplaceArg(args, options.atomicReplace);renamify-core/tests/coercion_tests.rs (1)
119-120: Explicit atomic_config: None in tests is appropriate.Keeps legacy coercion behavior stable while the atomic feature is introduced. Consider a small helper to construct PlanOptions with common defaults to reduce duplication.
Also applies to: 219-220, 285-286, 384-385, 485-486, 546-547, 622-623
renamify-core/src/config.rs (2)
11-14: Config surface addition looks good; confirm case-sensitivity expectations.If matching is case-sensitive (DocSpring vs docspring), mention it in the doc comment for fewer surprises.
152-167: Solid parsing test for atomic identifiers.Optional: add a round-trip save/load test and assert default is empty in test_default_config.
renamify-cli/src/plan.rs (1)
56-66: AtomicConfig construction logic reads well; minor simplification possible.from_flags_and_config already treats atomic_both as authoritative; computing the ORs is fine but slightly redundant.
renamify-vscode/webview/src/webview.ts (1)
36-47: Null-safety for optional checkboxes.Guard against template mismatches to avoid runtime errors and default to false in payload/state.
- const renamePathsCheckbox = document.getElementById( - 'renamePathsCheckbox' - ) as HTMLInputElement; + const renamePathsCheckbox = document.getElementById( + 'renamePathsCheckbox' + ) as HTMLInputElement | null; - const ignoreAmbiguousCheckbox = document.getElementById( - 'ignoreAmbiguousCheckbox' - ) as HTMLInputElement; + const ignoreAmbiguousCheckbox = document.getElementById( + 'ignoreAmbiguousCheckbox' + ) as HTMLInputElement | null; - const atomicSearchCheckbox = document.getElementById( - 'atomicSearchCheckbox' - ) as HTMLInputElement; + const atomicSearchCheckbox = document.getElementById( + 'atomicSearchCheckbox' + ) as HTMLInputElement | null; - const atomicReplaceCheckbox = document.getElementById( - 'atomicReplaceCheckbox' - ) as HTMLInputElement; + const atomicReplaceCheckbox = document.getElementById( + 'atomicReplaceCheckbox' + ) as HTMLInputElement | null;- renamePathsCheckbox.addEventListener('change', () => { + renamePathsCheckbox?.addEventListener('change', () => { performSearch(); saveState(); }); - ignoreAmbiguousCheckbox.addEventListener('change', () => { + ignoreAmbiguousCheckbox?.addEventListener('change', () => { performSearch(); saveState(); }); - atomicSearchCheckbox.addEventListener('change', () => { + atomicSearchCheckbox?.addEventListener('change', () => { performSearch(); saveState(); }); - atomicReplaceCheckbox.addEventListener('change', () => { + atomicReplaceCheckbox?.addEventListener('change', () => { performSearch(); saveState(); });- renamePaths: renamePathsCheckbox.checked, - ignoreAmbiguous: ignoreAmbiguousCheckbox.checked, - atomicSearch: atomicSearchCheckbox.checked, - atomicReplace: atomicReplaceCheckbox.checked, + renamePaths: renamePathsCheckbox?.checked ?? false, + ignoreAmbiguous: ignoreAmbiguousCheckbox?.checked ?? false, + atomicSearch: atomicSearchCheckbox?.checked ?? false, + atomicReplace: atomicReplaceCheckbox?.checked ?? false,- renamePaths: renamePathsCheckbox.checked, - ignoreAmbiguous: ignoreAmbiguousCheckbox.checked, - atomicSearch: atomicSearchCheckbox.checked, - atomicReplace: atomicReplaceCheckbox.checked, + renamePaths: renamePathsCheckbox?.checked ?? false, + ignoreAmbiguous: ignoreAmbiguousCheckbox?.checked ?? false, + atomicSearch: atomicSearchCheckbox?.checked ?? false, + atomicReplace: atomicReplaceCheckbox?.checked ?? false,- if (state.renamePaths !== undefined) { - renamePathsCheckbox.checked = state.renamePaths; - } + if (state.renamePaths !== undefined && renamePathsCheckbox) { + renamePathsCheckbox.checked = state.renamePaths; + } - if (state.ignoreAmbiguous !== undefined) { - ignoreAmbiguousCheckbox.checked = state.ignoreAmbiguous; - } + if (state.ignoreAmbiguous !== undefined && ignoreAmbiguousCheckbox) { + ignoreAmbiguousCheckbox.checked = state.ignoreAmbiguous; + } - if (state.atomicSearch !== undefined) { - atomicSearchCheckbox.checked = state.atomicSearch; - } + if (state.atomicSearch !== undefined && atomicSearchCheckbox) { + atomicSearchCheckbox.checked = state.atomicSearch; + } - if (state.atomicReplace !== undefined) { - atomicReplaceCheckbox.checked = state.atomicReplace; - } + if (state.atomicReplace !== undefined && atomicReplaceCheckbox) { + atomicReplaceCheckbox.checked = state.atomicReplace; + }- renamePaths: renamePathsCheckbox.checked, - ignoreAmbiguous: ignoreAmbiguousCheckbox.checked, - atomicSearch: atomicSearchCheckbox.checked, - atomicReplace: atomicReplaceCheckbox.checked, + renamePaths: renamePathsCheckbox?.checked ?? false, + ignoreAmbiguous: ignoreAmbiguousCheckbox?.checked ?? false, + atomicSearch: atomicSearchCheckbox?.checked ?? false, + atomicReplace: atomicReplaceCheckbox?.checked ?? false,Also applies to: 182-199, 264-268, 295-299, 809-822, 839-845
renamify-core/tests/format_string_test.rs (1)
52-54: Fix misleading parameter comments (these are acronym lists, not atomic flags).These three Vec params are include_acronyms, exclude_acronyms, only_acronyms. The current comments suggest atomic flags, which is incorrect and confusing.
Apply this diff:
- vec![], // custom_acronyms - vec![], // atomic_search - vec![], // atomic_replace + vec![], // include_acronyms + vec![], // exclude_acronyms + vec![], // only_acronymsrenamify-core/tests/exact_match_preserve_test.rs (1)
1285-1296: Avoid mentioning Dot-case here unless explicitly included in styles.Default styles exclude Dot, so referencing "doc.spring" in the allowed set is slightly misleading. Consider dropping it or adding Dot to the styles for this test.
Apply this diff (option A: drop Dot-case from the assertion text and allowed set):
- assert!( - formapi_value == "doc_spring" - || formapi_value == "doc-spring" - || formapi_value == "doc.spring" - ); + assert!( + formapi_value == "doc_spring" + || formapi_value == "doc-spring" + );Option B: include Dot explicitly in styles when building the map.
renamify-core/src/case_model.rs (1)
600-609: De-duplicate the default styles source.You already expose Style::default_styles(). Duplicating the list here risks drift. Build a Vec once and iterate over it.
Apply this diff:
- let default_styles = [ - Style::Snake, - Style::Kebab, - Style::Camel, - Style::Pascal, - Style::ScreamingSnake, - Style::Train, // Include Train-Case for patterns like Renamify-Core-Engine - Style::ScreamingTrain, // Include ScreamingTrain for patterns like RENAMIFY-DEBUG - ]; - let styles = styles.unwrap_or(&default_styles); + let default_styles_vec = Style::default_styles(); + let styles: &[Style] = styles.unwrap_or(&default_styles_vec);renamify-core/tests/ambiguity_integration_test.rs (1)
1-68: General: good coverage; consider printing matches only on failure.The eprintln! loop is noisy in passing runs. Wrap in a test-only debug flag or print on assertion failure.
renamify-core/src/atomic.rs (3)
6-16: TS export of HashSet may not map cleanly to TypeScriptts-rs support for HashSet is not universal. To avoid TS type-generation issues, annotate or switch to Vec for the wire type.
Apply one of:
pub struct AtomicConfig { - /// Set of identifiers that should be treated as atomic (indivisible) - pub atomic_identifiers: HashSet<String>, + /// Set of identifiers that should be treated as atomic (indivisible) + #[ts(type = "Array<string>")] + pub atomic_identifiers: HashSet<String>,or:
- pub atomic_identifiers: HashSet<String>, + pub atomic_identifiers: Vec<String>,If you switch to Vec, normalize into a HashSet internally in from_flags_and_config.
23-33: Case-insensitive match is ASCII-onlyeq_ignore_ascii_case() skips non-ASCII. If users add non-ASCII identifiers (e.g., “München”), comparisons will fail.
- .any(|atomic| atomic.eq_ignore_ascii_case(identifier)) + .any(|atomic| atomic.to_lowercase() == identifier.to_lowercase())This is slower but correct. If perf matters, consider unicode casefolding (unicode-normalization).
78-109: Camel-case lowering is fine; consider caching for repeated callsto_atomic_style allocates per call. If used in tight loops (variant gen), consider small caching when styles.len() is large. Not urgent.
renamify-core/src/ambiguity/resolver.rs (1)
80-87: Reduce repeated env var checks for debug loggingCache the debug flag once.
- if std::env::var("RENAMIFY_DEBUG_AMBIGUITY").is_ok() { + let debug = std::env::var("RENAMIFY_DEBUG_AMBIGUITY").is_ok(); + if debug { eprintln!( "=== Resolving ambiguity for '{}' -> '{}' ===", matched_text, replacement_text ); - eprintln!(" File: {:?}", context.file_path); - eprintln!(" Content: {:?}", context.line_content); + eprintln!(" File: {:?}", context.file_path); + eprintln!(" Content: {:?}", context.line_content); } ... - if std::env::var("RENAMIFY_DEBUG_AMBIGUITY").is_ok() { + if debug { eprintln!(" -> Not ambiguous, detected style: {:?}", style); }Propagate debug where used.
Also applies to: 92-95, 114-116, 122-124, 130-133
renamify-core/src/scanner.rs (4)
62-64: TS/serde surface for AtomicConfigPlanOptions exposes atomic_config over TS. Given AtomicConfig.atomic_identifiers is a HashSet, ensure ts-rs can generate correct TS. If not, add #[ts(type = "...")] on the AtomicConfig field or switch to Vec as suggested in atomic.rs.
Also applies to: 101-102
457-462: Avoid re-tokenizing replacement on every ambiguous matchCache tokens once per file.
- // Calculate possible styles for the replacement text ONCE for all matches in this file - let replacement_possible_styles = get_possible_styles(original_replacement); + // Calculate once per file + let replacement_possible_styles = get_possible_styles(original_replacement); + let replacement_tokens_cache = parse_to_tokens(original_replacement); ... - let replacement_tokens = parse_to_tokens(original_replacement); - let styled_replacement = to_style(&replacement_tokens, resolved.style); + let styled_replacement = to_style(&replacement_tokens_cache, resolved.style);Also applies to: 520-523
381-389: Plan.version should be consistent with create_simple_planscan_repository_multi hardcodes "1.0.0" while create_simple_plan uses env!("CARGO_PKG_VERSION"). Prefer the latter for consistency.
- version: "1.0.0".to_string(), + version: env!("CARGO_PKG_VERSION").to_string(),
405-424: Directory glob heuristic may overmatch single-file namesHeuristic treats patterns without wildcards and without dots as directories (e.g., "LICENSE"). This can unintentionally expand to "LICENSE/**".
Consider checking filesystem when roots are known, or require a trailing slash to opt-in to recursive dir match.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (51)
.taskmaster/docs/atomic-prd.txt(1 hunks)CLAUDE.md(1 hunks)docs/astro.config.mjs(1 hunks)docs/src/content/docs/commands/plan.mdx(2 hunks)docs/src/content/docs/commands/rename.mdx(2 hunks)docs/src/content/docs/commands/search.mdx(2 hunks)docs/src/content/docs/features/atomic-identifiers.mdx(1 hunks)docs/src/content/docs/mcp/tools.mdx(5 hunks)renamify-cli/.gitignore(1 hunks)renamify-cli/src/cli/args.rs(3 hunks)renamify-cli/src/main.rs(4 hunks)renamify-cli/src/plan.rs(4 hunks)renamify-cli/src/replace.rs(1 hunks)renamify-cli/tests/binary_name_preservation.rs(1 hunks)renamify-cli/tests/cli_tests.rs(3 hunks)renamify-core/src/ambiguity/language_heuristics.rs(1 hunks)renamify-core/src/ambiguity/mod.rs(3 hunks)renamify-core/src/ambiguity/resolver.rs(6 hunks)renamify-core/src/atomic.rs(1 hunks)renamify-core/src/case_model.rs(9 hunks)renamify-core/src/config.rs(2 hunks)renamify-core/src/lib.rs(1 hunks)renamify-core/src/operations/plan.rs(2 hunks)renamify-core/src/operations/rename.rs(1 hunks)renamify-core/src/scanner.rs(10 hunks)renamify-core/tests/acronym_cli_test.rs(5 hunks)renamify-core/tests/acronym_variant_test.rs(5 hunks)renamify-core/tests/ambiguity_integration_test.rs(1 hunks)renamify-core/tests/coercion_separator_test.rs(11 hunks)renamify-core/tests/coercion_tests.rs(7 hunks)renamify-core/tests/compound_position_test.rs(4 hunks)renamify-core/tests/compound_word_test.rs(13 hunks)renamify-core/tests/diff_rendering_test.rs(2 hunks)renamify-core/tests/dot_directory_test.rs(4 hunks)renamify-core/tests/exact_match_preserve_test.rs(1 hunks)renamify-core/tests/format_string_test.rs(1 hunks)renamify-core/tests/hyphenated_capitalized_test.rs(5 hunks)renamify-core/tests/mixed_style_test.rs(3 hunks)renamify-core/tests/multiple_matches_per_line_test.rs(9 hunks)renamify-core/tests/replace_column_position_test.rs(3 hunks)renamify-core/tests/replace_include_flag_test.rs(3 hunks)renamify-core/tests/tokenization_edge_cases_test.rs(8 hunks)renamify-core/tests/train_case_apply_test.rs(1 hunks)renamify-core/tests/train_case_literals_test.rs(2 hunks)renamify-mcp/src/index.ts(3 hunks)renamify-mcp/src/renamify-service.ts(7 hunks)renamify-vscode/extension/src/cliService.ts(3 hunks)renamify-vscode/extension/src/types.ts(4 hunks)renamify-vscode/extension/templates/webview.hbs(1 hunks)renamify-vscode/media/style.css(1 hunks)renamify-vscode/webview/src/webview.ts(7 hunks)
🧰 Additional context used
🧬 Code graph analysis (9)
renamify-core/tests/format_string_test.rs (1)
renamify-core/src/operations/plan.rs (1)
plan_operation(10-144)
renamify-core/tests/exact_match_preserve_test.rs (3)
renamify-core/src/case_model.rs (2)
generate_variant_map(585-591)generate_variant_map_with_atomic(593-686)renamify-core/src/scanner.rs (1)
get(802-819)renamify-core/src/atomic.rs (1)
from_flags_and_config(36-59)
renamify-core/tests/ambiguity_integration_test.rs (1)
renamify-core/src/operations/plan.rs (1)
plan_operation(10-144)
renamify-core/src/atomic.rs (2)
renamify-core/src/scanner.rs (2)
new(785-787)default(82-103)renamify-core/src/case_model.rs (3)
new(43-45)new(54-56)first(581-581)
renamify-core/src/scanner.rs (2)
renamify-core/src/ambiguity/mod.rs (2)
get_possible_styles(114-136)is_ambiguous(139-141)renamify-core/src/case_model.rs (5)
parse_to_tokens(186-188)to_style(450-567)new(43-45)new(54-56)generate_variant_map_with_atomic(593-686)
renamify-core/src/case_model.rs (3)
renamify-core/src/atomic.rs (4)
new(19-21)parse_atomic(73-76)to_atomic_style(79-110)from_flags_and_config(36-59)renamify-core/src/acronym.rs (2)
new(52-58)get_default_acronym_set(17-19)renamify-core/src/ambiguity/mod.rs (1)
is_ambiguous(139-141)
renamify-core/src/ambiguity/resolver.rs (2)
renamify-core/src/ambiguity/mod.rs (2)
is_ambiguous(139-141)get_possible_styles(114-136)renamify-core/src/case_model.rs (1)
detect_style(59-154)
renamify-core/tests/multiple_matches_per_line_test.rs (1)
renamify-core/src/scanner.rs (1)
scan_repository(204-206)
renamify-cli/src/plan.rs (2)
renamify-core/src/config.rs (1)
load(61-71)renamify-core/src/atomic.rs (1)
from_flags_and_config(36-59)
🪛 LanguageTool
.taskmaster/docs/atomic-prd.txt
[grammar] ~3-~3: There might be a mistake here.
Context: ...uirements Document ## Executive Summary Add support for treating certain identif...
(QB_NEW_EN)
[grammar] ~6-~6: There might be a mistake here.
Context: ...n all case styles. ## Problem Statement Currently, when renaming identifiers lik...
(QB_NEW_EN)
[grammar] ~22-~22: There might be a mistake here.
Context: ...tory 1: CLI User with Atomic Identifiers As a developer renaming "HubGit" to "Git...
(QB_NEW_EN)
[grammar] ~23-~23: There might be a mistake here.
Context: ...ing "HubGit" to "GitHub" in my codebase, I want to specify that both names are at...
(QB_NEW_EN)
[grammar] ~27-~27: There might be a mistake here.
Context: ...ect with Persistent Atomic Configuration As a team maintaining a project with bra...
(QB_NEW_EN)
[style] ~29-~29: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...ct with brand names like "DocSpring", I want to configure these as atomic in a config f...
(REP_WANT_TO_VB)
[grammar] ~32-~32: There might be a mistake here.
Context: ...or. ### Story 3: VS Code Extension User As a VS Code user, I want checkboxes to ...
(QB_NEW_EN)
[grammar] ~33-~33: There might be a mistake here.
Context: ...S Code Extension User As a VS Code user, I want checkboxes to mark search/replace...
(QB_NEW_EN)
[grammar] ~37-~37: There might be a mistake here.
Context: ...y. ### Story 4: Partial Atomic Matching As a developer with "FormAPIController" ...
(QB_NEW_EN)
[grammar] ~38-~38: There might be a mistake here.
Context: ...per with "FormAPIController" in my code, I want atomic "FormAPI" to match and rep...
(QB_NEW_EN)
[grammar] ~44-~44: There might be a mistake here.
Context: ...quirements ### 1. Core Atomic Detection - When an identifier is marked as atomic, ...
(QB_NEW_EN)
[grammar] ~51-~51: There might be a mistake here.
Context: ...eplace are atomic - --atomic-search - Only search term is atomic - `--atomic-repla...
(QB_NEW_EN)
[style] ~52-~52: This adverb was used twice in the sentence. Consider removing one of them or replacing them with a synonym.
Context: ...h term is atomic - --atomic-replace - Only replace term is atomic - --no-atomic ...
(ADVERB_REPETITION_PREMIUM)
[grammar] ~54-~54: There might be a mistake here.
Context: ... --no-atomic-search - Override config for search term - --no-atomic-replace - O...
(QB_NEW_EN)
[grammar] ~55-~55: There might be a mistake here.
Context: ...--no-atomic-replace - Override config for replace term - Error if user specifies ...
(QB_NEW_EN)
[grammar] ~56-~56: There might be a mistake here.
Context: ...verride config for replace term - Error if user specifies both --atomic and `--a...
(QB_NEW_EN)
[grammar] ~58-~58: There might be a mistake here.
Context: ...omic-replace ### 3. Configuration File - Supportatomic = ["DocSpring", "GitHub"...
(QB_NEW_EN)
[grammar] ~59-~59: There might be a mistake here.
Context: ...= ["DocSpring", "GitHub", "GitHub"]in.renamify/config.toml` - Config entries are case-insensitive matc...
(QB_NEW_EN)
[grammar] ~64-~64: There might be a mistake here.
Context: ...nfig settings ### 4. Variant Generation For atomic identifier "DocSpring": - Gen...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a mistake here.
Context: ...ation For atomic identifier "DocSpring": - Generate only: DocSpring, docspring,...
(QB_NEW_EN)
[grammar] ~69-~69: There might be a mistake here.
Context: ...ng ### 5. Compound Identifier Handling When "FormAPI" is atomic: -FormAPICont...
(QB_NEW_EN)
[grammar] ~76-~76: There might be a mistake here.
Context: ...er identifiers ### 6. VS Code Extension - Add "Atomic" checkbox under Search field...
(QB_NEW_EN)
[grammar] ~82-~82: There might be a mistake here.
Context: ... match config entries ### 7. MCP Server - Add atomicSearch: boolean parameter - ...
(QB_NEW_EN)
[grammar] ~89-~89: There might be a mistake here.
Context: ...uirements ### 1. Case Model Refactoring - Split case_model.rs into smaller modul...
(QB_NEW_EN)
[grammar] ~94-~94: There might be a mistake here.
Context: ...d compatibility ### 2. Token Generation - Modify parse_to_tokens to accept atomi...
(QB_NEW_EN)
[grammar] ~96-~96: There might be a mistake here.
Context: ...` to accept atomic hints - When atomic, return single token regardless of internal cap...
(QB_NEW_EN)
[grammar] ~99-~99: There might be a mistake here.
Context: ...ot atomic ### 3. Variant Map Generation - Update generate_variant_map to accept ...
(QB_NEW_EN)
[grammar] ~104-~104: There might be a mistake here.
Context: ...mic/non-atomic scenarios ### 4. Testing - Unit tests for atomic token parsing - In...
(QB_NEW_EN)
[grammar] ~105-~105: There might be a mistake here.
Context: ...ng - Unit tests for atomic token parsing - Integration tests for compound identifie...
(QB_NEW_EN)
[grammar] ~106-~106: There might be a mistake here.
Context: ...tegration tests for compound identifiers - End-to-end tests with real examples (Doc...
(QB_NEW_EN)
[grammar] ~107-~107: There might be a mistake here.
Context: ...s with real examples (DocSpring, GitHub) - Performance tests to ensure no regressio...
(QB_NEW_EN)
[grammar] ~112-~112: There might be a mistake here.
Context: ...ctional Requirements ### 1. Performance - Atomic detection should not significantl...
(QB_NEW_EN)
[grammar] ~117-~117: There might be a mistake here.
Context: ...tion - Create "Atomic Identifiers" page in Features section - Include examples of ...
(QB_NEW_EN)
[grammar] ~119-~119: There might be a mistake here.
Context: ...e examples of when to use atomic mode - Document config file format ### 3. Error Handli...
(QB_NEW_EN)
[grammar] ~121-~121: There might be a mistake here.
Context: ...onfig file format ### 3. Error Handling - Clear error messages for conflicting fla...
(QB_NEW_EN)
[grammar] ~164-~164: There might be a mistake here.
Context: ...Plan ### Phase 1: Core Support (Week 1) 1. Refactor case_model.rs into modules 2. I...
(QB_NEW_EN)
[grammar] ~170-~170: There might be a mistake here.
Context: ...s ### Phase 2: CLI Integration (Week 1) 1. Add CLI flags 2. Implement config file s...
(QB_NEW_EN)
[grammar] ~176-~176: There might be a mistake here.
Context: ...ts ### Phase 3: UI Integration (Week 2) 1. Update VS Code extension 2. Update MCP s...
(QB_NEW_EN)
[grammar] ~182-~182: There might be a mistake here.
Context: ...ing ### Phase 4: Documentation (Week 2) 1. Create atomic identifiers documentation ...
(QB_NEW_EN)
[grammar] ~187-~187: There might be a mistake here.
Context: ...README and help text ## Success Metrics - All test cases pass - No performance reg...
(QB_NEW_EN)
[grammar] ~195-~195: There might be a mistake here.
Context: ...itigations ### Risk 1: Breaking Changes Mitigation: Atomic mode is opt-in, exi...
(QB_NEW_EN)
[grammar] ~198-~198: There might be a mistake here.
Context: ... default ### Risk 2: Performance Impact Mitigation: Early detection during par...
(QB_NEW_EN)
[grammar] ~201-~201: There might be a mistake here.
Context: ...before/after ### Risk 3: User Confusion Mitigation: Clear documentation, intui...
(QB_NEW_EN)
docs/src/content/docs/commands/rename.mdx
[grammar] ~73-~73: There might be a mistake here.
Context: ...isible units - --atomic-search - Only treat search term as atomic - `--atomic-repla...
(QB_NEW_EN)
[grammar] ~74-~74: There might be a mistake here.
Context: ...m as atomic - --atomic-replace - Only treat replace term as atomic - --no-atomic ...
(QB_NEW_EN)
[grammar] ~76-~76: There might be a mistake here.
Context: ...- --no-atomic-search - Disable atomic for search term - --no-atomic-replace - D...
(QB_NEW_EN)
[grammar] ~77-~77: There might be a mistake here.
Context: ... --no-atomic-replace - Disable atomic for replace term ### Display Options - `-...
(QB_NEW_EN)
docs/src/content/docs/commands/plan.mdx
[grammar] ~64-~64: There might be a mistake here.
Context: ...isible units - --atomic-search - Only treat search term as atomic - `--atomic-repla...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a mistake here.
Context: ...m as atomic - --atomic-replace - Only treat replace term as atomic - --no-atomic ...
(QB_NEW_EN)
[grammar] ~67-~67: There might be a mistake here.
Context: ...- --no-atomic-search - Disable atomic for search term - --no-atomic-replace - D...
(QB_NEW_EN)
[grammar] ~68-~68: There might be a mistake here.
Context: ... --no-atomic-replace - Disable atomic for replace term ### Display Options - `-...
(QB_NEW_EN)
docs/src/content/docs/features/atomic-identifiers.mdx
[grammar] ~125-~125: There might be a mistake here.
Context: ...yle | Non-Atomic | Atomic | | -------------------- | ---------- | --...
(QB_NEW_EN)
[grammar] ~126-~126: There might be a mistake here.
Context: ...------------- | ---------- | --------- | | snake_case | doc_spring | do...
(QB_NEW_EN)
[grammar] ~127-~127: There might be a mistake here.
Context: ...ase | doc_spring | docspring | | kebab-case | doc-spring | do...
(QB_NEW_EN)
[grammar] ~128-~128: There might be a mistake here.
Context: ...ase | doc-spring | docspring | | camelCase | docSpring | do...
(QB_NEW_EN)
[grammar] ~129-~129: There might be a mistake here.
Context: ...se | docSpring | docspring | | PascalCase | DocSpring | Do...
(QB_NEW_EN)
[grammar] ~130-~130: There might be a mistake here.
Context: ...ase | DocSpring | DocSpring | | SCREAMING_SNAKE_CASE | DOC_SPRING | DO...
(QB_NEW_EN)
[grammar] ~131-~131: There might be a mistake here.
Context: ...NG_SNAKE_CASE | DOC_SPRING | DOCSPRING | | Train-Case | Doc-Spring | Do...
(QB_NEW_EN)
[grammar] ~132-~132: There might be a mistake here.
Context: ...ase | Doc-Spring | Docspring | | lowercase | docspring | do...
(QB_NEW_EN)
[grammar] ~133-~133: There might be a mistake here.
Context: ...se | docspring | docspring | | UPPERCASE | DOCSPRING | DO...
(QB_NEW_EN)
[grammar] ~147-~147: There might be a mistake here.
Context: ...Add frequently used brand names to your .renamify/config.toml 2. Use for Compound Words: Apply atomic m...
(QB_NEW_EN)
[grammar] ~166-~166: There might be a mistake here.
Context: ...ations required - Config file is cached after first read ## Limitations - Atomic mo...
(QB_NEW_EN)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Test on ubuntu-latest
- GitHub Check: Test VS Code Extension (ubuntu-latest, 20.x)
- GitHub Check: Test VS Code Extension (macos-latest, 20.x)
- GitHub Check: Test VS Code Extension (windows-latest, 20.x)
- GitHub Check: Test on macos-latest
- GitHub Check: Test on windows-latest
- GitHub Check: Self-Hosting Demo (ubuntu-latest)
- GitHub Check: Self-Hosting Demo (windows-latest)
- GitHub Check: Self-Hosting Demo (macos-latest)
| - 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate “GitHub” in config example
Deduplicate to avoid implying duplicates are meaningful.
- - Support `atomic = ["DocSpring", "GitHub", "GitHub"]` in `.renamify/config.toml`
+ - Support `atomic = ["DocSpring", "GitHub"]` in `.renamify/config.toml`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - 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 | |
| - Support `atomic = ["DocSpring", "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 |
🧰 Tools
🪛 LanguageTool
[grammar] ~59-~59: There might be a mistake here.
Context: ...= ["DocSpring", "GitHub", "GitHub"]in.renamify/config.toml` - Config entries are case-insensitive matc...
(QB_NEW_EN)
🤖 Prompt for AI Agents
.taskmaster/docs/atomic-prd.txt around lines 59-61: the example list for atomic
in `.renamify/config.toml` contains a duplicate "GitHub"; remove the duplicate
so each provider appears only once (e.g., `atomic = ["DocSpring", "GitHub"]`)
and update any surrounding text if it refers to duplicates so the example no
longer implies duplicates are meaningful.
| - `git_lab_api` → `GitHub_api` | ||
| - `GIT_LAB_TOKEN` → `GitHub_TOKEN` | ||
| - `GitLabController` → `GitHubController` | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect acceptance examples for atomic mapping
Atomic GitLab → GitHub should map styles consistently:
- git_lab_api → github_api
- GIT_LAB_TOKEN → GITHUB_TOKEN
Current examples mix cases (GitHub_api, GitHub_TOKEN).
- - `git_lab_api` → `GitHub_api`
- - `GIT_LAB_TOKEN` → `GitHub_TOKEN`
+ - `git_lab_api` → `github_api`
+ - `GIT_LAB_TOKEN` → `GITHUB_TOKEN`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - `git_lab_api` → `GitHub_api` | |
| - `GIT_LAB_TOKEN` → `GitHub_TOKEN` | |
| - `GitLabController` → `GitHubController` | |
| - `git_lab_api` → `github_api` | |
| - `GIT_LAB_TOKEN` → `GITHUB_TOKEN` | |
| - `GitLabController` → `GitHubController` |
🤖 Prompt for AI Agents
In .taskmaster/docs/atomic-prd.txt around lines 131 to 134, the acceptance
examples for the atomic GitLab→GitHub mapping use inconsistent casing (e.g.,
GitHub_api, GitHub_TOKEN); update the examples so they consistently use
lowercase/hyphenation as specified: replace `GitHub_api` with `github_api` and
`GitHub_TOKEN` with `GITHUB_TOKEN` (and likewise ensure `GitLabController`
becomes `GitHubController` only if controller naming should follow the same
casing rules), so all examples consistently reflect `git_lab_api` → `github_api`
and `GIT_LAB_TOKEN` → `GITHUB_TOKEN`.
| `.renamify/config.toml` | ||
|
|
||
| - Project configuration including atomic identifiers | ||
| - `atomic = ["DocSpring", "GitHub", "GitHub"]` - identifiers treated as indivisible units | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate identifier in example atomic list
"GitHub" appears twice. Deduplicate to avoid confusing users configuring atomic identifiers.
-- `atomic = ["DocSpring", "GitHub", "GitHub"]` - identifiers treated as indivisible units
+- `atomic = ["DocSpring", "GitHub"]` - identifiers treated as indivisible units📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| `.renamify/config.toml` | |
| - Project configuration including atomic identifiers | |
| - `atomic = ["DocSpring", "GitHub", "GitHub"]` - identifiers treated as indivisible units | |
| `.renamify/config.toml` | |
| - Project configuration including atomic identifiers | |
| - `atomic = ["DocSpring", "GitHub"]` - identifiers treated as indivisible units |
🤖 Prompt for AI Agents
In CLAUDE.md around lines 139 to 143, the example atomic list contains a
duplicate "GitHub" entry; update the example to remove the duplicate so each
identifier appears only once (e.g., change atomic = ["DocSpring", "GitHub"]) and
ensure the documentation text reflects that atomic identifiers should be unique
to avoid user confusion.
| <Tabs> | ||
| <TabItem label="Both atomic"> | ||
| ```bash # Both search and replace terms are atomic renamify rename FormAPI | ||
| DocSpring --atomic | ||
| ``` | ||
| </TabItem> | ||
| <TabItem label="Search only"> | ||
| ```bash # Only search term is atomic renamify rename FormAPI Helper | ||
| --atomic-search | ||
| ``` | ||
| </TabItem> | ||
| <TabItem label="Replace only"> | ||
|
|
||
| ```bash # Only replace term is atomic renamify rename OldName DocSpring | ||
| --atomic-replace | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| </Tabs> | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix broken CLI examples in tabs.
Code blocks mix comments and incomplete commands; render incorrectly. Replace with valid commands.
<Tabs>
<TabItem label="Both atomic">
- ```bash # Both search and replace terms are atomic renamify rename FormAPI
- DocSpring --atomic
+ ```bash
+ renamify rename FormAPI DocSpring --atomic🤖 Prompt for AI Agents
In docs/src/content/docs/features/atomic-identifiers.mdx around lines 47–66 the
CLI examples are broken (comments and partial commands inside code fences);
replace each TabItem's code block with a proper fenced bash block containing the
full renamify commands: for "Both atomic" use renamify rename FormAPI DocSpring
--atomic, for "Search only" use renamify rename FormAPI Helper --atomic-search,
and for "Replace only" use renamify rename OldName DocSpring --atomic-replace;
ensure each block begins with ```bash on its own line and ends with ``` on its
own line so the examples render correctly.
| /// 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 (DocSpring → docspring, not doc_spring) | ||
| #[arg(long)] | ||
| pub atomic_search: bool, | ||
|
|
||
| /// Treat replace term as atomic (DocSpring → docspring, not doc_spring) | ||
| #[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, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Tighten mutually exclusive flags for atomic options
no_atomic should also conflict with atomic_search and atomic_replace to prevent contradictory inputs.
- #[arg(long, conflicts_with = "atomic")]
+ #[arg(long, conflicts_with_all = ["atomic", "atomic_search", "atomic_replace"])]
pub no_atomic: bool,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /// 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 (DocSpring → docspring, not doc_spring) | |
| #[arg(long)] | |
| pub atomic_search: bool, | |
| /// Treat replace term as atomic (DocSpring → docspring, not doc_spring) | |
| #[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, | |
| } | |
| /// 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 (DocSpring → docspring, not doc_spring) | |
| #[arg(long)] | |
| pub atomic_search: bool, | |
| /// Treat replace term as atomic (DocSpring → docspring, not doc_spring) | |
| #[arg(long)] | |
| pub atomic_replace: bool, | |
| /// Override config: allow word boundary detection | |
| #[arg(long, conflicts_with_all = ["atomic", "atomic_search", "atomic_replace"])] | |
| 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, | |
| } |
🤖 Prompt for AI Agents
In renamify-cli/src/cli/args.rs around lines 124 to 150, the no_atomic flag
currently only conflicts with atomic; update its attribute to also conflict with
atomic_search and atomic_replace to avoid contradictory inputs — replace the
existing #[arg(long, conflicts_with = "atomic")] with #[arg(long,
conflicts_with_all = ["atomic", "atomic_search", "atomic_replace"])], keeping
the rest of the struct unchanged.
| None, // cwd | ||
| None, // atomic_config | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the temp directory as working_dir to avoid a global .renamify lock.
Without passing working_dir, LockFile::acquire runs under the process CWD, risking cross-test interference and unexpected writes outside the temp dir.
Apply this diff:
- None, // cwd
+ Some(temp_path), // cwd - ensure lock & plan live under the temp dir
None, // atomic_config📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| None, // cwd | |
| None, // atomic_config | |
| ) | |
| Some(temp_path), // cwd - ensure lock & plan live under the temp dir | |
| None, // atomic_config | |
| ) |
🤖 Prompt for AI Agents
In renamify-core/tests/format_string_test.rs around lines 55 to 57, the call
currently leaves working_dir as None which causes LockFile::acquire to use the
process CWD and can clash across tests; update the call to pass the test's
temporary directory as the working_dir (wrap the temp dir path in Some and
convert to the expected Path/PathBuf type as needed) so the lock is acquired
inside the temp directory and avoids a global .renamify lock.
| for m in &matches { | ||
| if m.content == "greattool" { | ||
| if let Some(ref line_before) = m.line_before { | ||
| if line_before.contains("greattool_") { | ||
| assert_eq!( | ||
| m.replace, "awesome_tool_name", | ||
| "Format string with double curly brackets should preserve snake_case, got: {}", | ||
| m.replace | ||
| ); | ||
| // The full line should have the underscore preserved | ||
| if let Some(ref line_after) = m.line_after { | ||
| assert!( | ||
| line_after.contains("awesome_tool_name_"), | ||
| "Line should contain 'awesome_tool_name_', got: {}", | ||
| line_after | ||
| ); | ||
| } | ||
| // Make sure it's NOT lowercase without underscores | ||
| assert_ne!( | ||
| m.replace, "awesometoolname", | ||
| "Should NOT be all lowercase without underscores" | ||
| ); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The snake_case context check looks at line_before but should inspect line_after.
For a match on "greattool" inside "greattool_{{}}.tmp", the underscore follows the match; line_after should be used. Also, asserting that line_after contains "awesome_tool_name_" is invalid because line_after reflects original text, not the replaced line.
Apply this diff:
- if m.content == "greattool" {
- if let Some(ref line_before) = m.line_before {
- if line_before.contains("greattool_") {
- assert_eq!(
- m.replace, "awesome_tool_name",
- "Format string with double curly brackets should preserve snake_case, got: {}",
- m.replace
- );
- // The full line should have the underscore preserved
- if let Some(ref line_after) = m.line_after {
- assert!(
- line_after.contains("awesome_tool_name_"),
- "Line should contain 'awesome_tool_name_', got: {}",
- line_after
- );
- }
- // Make sure it's NOT lowercase without underscores
- assert_ne!(
- m.replace, "awesometoolname",
- "Should NOT be all lowercase without underscores"
- );
- }
- }
- }
+ if m.content == "greattool" {
+ if let Some(ref after) = m.line_after {
+ // Underscore immediately after the match indicates snake_case context
+ if after.starts_with('_') {
+ assert_eq!(
+ m.replace, "awesome_tool_name",
+ "Format string with double curly brackets should preserve snake_case, got: {}",
+ m.replace
+ );
+ // Ensure the source retains the trailing underscore after the match
+ assert!(
+ after.starts_with('_'),
+ "Expected '_' immediately after match, got: {}",
+ after
+ );
+ // Not smashed into all lowercase without separators
+ assert_ne!(
+ m.replace, "awesometoolname",
+ "Should NOT be all lowercase without underscores"
+ );
+ }
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for m in &matches { | |
| if m.content == "greattool" { | |
| if let Some(ref line_before) = m.line_before { | |
| if line_before.contains("greattool_") { | |
| assert_eq!( | |
| m.replace, "awesome_tool_name", | |
| "Format string with double curly brackets should preserve snake_case, got: {}", | |
| m.replace | |
| ); | |
| // The full line should have the underscore preserved | |
| if let Some(ref line_after) = m.line_after { | |
| assert!( | |
| line_after.contains("awesome_tool_name_"), | |
| "Line should contain 'awesome_tool_name_', got: {}", | |
| line_after | |
| ); | |
| } | |
| // Make sure it's NOT lowercase without underscores | |
| assert_ne!( | |
| m.replace, "awesometoolname", | |
| "Should NOT be all lowercase without underscores" | |
| ); | |
| } | |
| } | |
| for m in &matches { | |
| if m.content == "greattool" { | |
| if let Some(ref after) = m.line_after { | |
| // Underscore immediately after the match indicates snake_case context | |
| if after.starts_with('_') { | |
| assert_eq!( | |
| m.replace, "awesome_tool_name", | |
| "Format string with double curly brackets should preserve snake_case, got: {}", | |
| m.replace | |
| ); | |
| // Ensure the source retains the trailing underscore after the match | |
| assert!( | |
| after.starts_with('_'), | |
| "Expected '_' immediately after match, got: {}", | |
| after | |
| ); | |
| // Not smashed into all lowercase without separators | |
| assert_ne!( | |
| m.replace, "awesometoolname", | |
| "Should NOT be all lowercase without underscores" | |
| ); | |
| } | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In renamify-core/tests/format_string_test.rs around lines 74 to 97, the test
currently checks for a trailing underscore by inspecting line_before and then
asserts line_after contains the replaced string with an underscore, which is
wrong: the underscore follows the match so you must inspect line_after (not
line_before), and you must not assert line_after contains "awesome_tool_name_"
because line_after is the original context (pre-replacement). Change the check
to use line_after (e.g., assert that line_after starts_with or contains a
leading "_" immediately after the match) and remove the assertion that expects
"awesome_tool_name_" in line_after; keep the assert_eq on m.replace ==
"awesome_tool_name" and the assert_ne against "awesometoolname".
renamify-mcp/src/index.ts
Outdated
| atomicSearch: z | ||
| .boolean() | ||
| .optional() | ||
| .describe('Treat search term as atomic (indivisible unit)'), | ||
| atomicReplace: z | ||
| .boolean() | ||
| .optional() | ||
| .describe('Treat replace term as atomic (indivisible unit)'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Atomic flags added to plan: confirm propagation and defaults
Looks good. Please confirm RenamifyTools.plan/RenamifyService.plan accept and forward atomicSearch/atomicReplace to core. If unset, service should fall back to config (not falsey).
🏁 Script executed:
#!/bin/bash
# Trace MCP -> service -> core wiring for atomic flags
rg -n --context 2 -g 'renamify-mcp/**' '\batomic(Search|Replace)\b'
rg -n --context 3 -g 'renamify-mcp/**' 'plan\(params\)'
rg -n --context 3 -g 'renamify-mcp/**' 'search\(params\)'
rg -n --context 3 -g 'renamify-mcp/**' 'rename\(params\)'
# Service/Tools mapping
rg -n -C2 -g 'renamify-mcp/**' 'class RenamifyService|class RenamifyTools|plan\(.*\)|search\(.*\)|rename\(.*\)'
# Ensure CLI/core calls receive atomic flags
rg -n -C3 -g '!**/target/**' '\batomic(Search|Replace)\b'Length of output: 31990
Propagate atomicReplace in plan args builder
In renamify-mcp/src/renamify-service.ts’s buildPlanArgs (around line 169), only addAtomicSearchArg is called—addAtomicReplaceArg must also be invoked so the atomicReplace flag reaches the core.
🤖 Prompt for AI Agents
In renamify-mcp/src/renamify-service.ts around line 169, the buildPlanArgs
function invokes addAtomicSearchArg but never propagates the atomicReplace flag;
call addAtomicReplaceArg in the same place you call addAtomicSearchArg so the
atomicReplace option from the zod args is added to the constructed plan args
(ensure you pass the same args/plan/context parameters as used for
addAtomicSearchArg, add any missing import for addAtomicReplaceArg, and
run/update tests to cover the atomicReplace path).
| atomicSearch?: boolean; | ||
| atomicReplace?: boolean; | ||
| }): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Expose the rename options type or document inline shape.
Inline type is fine, but ensure MCP schema/index exports these fields and any client typings are updated.
Run:
🏁 Script executed:
#!/bin/bash
rg -n "atomic(Search|Replace)" renamify-mcp/src/index.ts renamify-mcp/src --type ts -C2Length of output: 6312
🏁 Script executed:
#!/bin/bash
rg -n "export type" -C5 renamify-mcp/src/index.ts
rg -n "z.infer" -C5 renamify-mcp/src/index.ts
rg -n "Options" -C5 renamify-mcp/src/index.tsLength of output: 143
Export rename options type
In renamify-mcp/src/index.ts, add and export a type alias for the rename-options schema (for example:
export type RenameOptions = z.infer<typeof renameSchema>;) so that atomicSearch and atomicReplace are part of the public API and reflected in client typings.
🤖 Prompt for AI Agents
In renamify-mcp/src/renamify-service.ts around lines 459-461 the rename options
include atomicSearch and atomicReplace but the public API lacks a typed export;
open renamify-mcp/src/index.ts and add an exported type alias such as "export
type RenameOptions = z.infer<typeof renameSchema>;", ensuring renameSchema is
imported or referenced from its module, and then export that type from the
package entry so atomicSearch and atomicReplace are included in client typings.
| <a | ||
| href="https://docspring.github.io/renamify/features/ambiguity-resolution/" | ||
| class="more-info-link" | ||
| target="_blank" | ||
| >more info</a | ||
| > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add rel="noopener noreferrer" to external link.
Prevents reverse tabnabbing from target="_blank" in webviews.
- <a
+ <a
href="https://docspring.github.io/renamify/features/ambiguity-resolution/"
class="more-info-link"
- target="_blank"
+ target="_blank" rel="noopener noreferrer"
>more info</a
>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <a | |
| href="https://docspring.github.io/renamify/features/ambiguity-resolution/" | |
| class="more-info-link" | |
| target="_blank" | |
| >more info</a | |
| > | |
| <a | |
| href="https://docspring.github.io/renamify/features/ambiguity-resolution/" | |
| class="more-info-link" | |
| target="_blank" rel="noopener noreferrer" | |
| >more info</a | |
| > |
🤖 Prompt for AI Agents
renamify-vscode/extension/templates/webview.hbs around lines 86 to 91: the
external anchor with target="_blank" lacks rel attributes; add rel="noopener
noreferrer" to the <a> tag to prevent reverse tabnabbing and ensure both
security and privacy, i.e., update the anchor element to include rel="noopener
noreferrer" alongside the existing target attribute.
Summary by CodeRabbit