Current State
src/core/mv.rs is ~1750 lines and is the heaviest core file in the repo. It mixes at least six concerns in one module:
- path validation (
validate_move_paths, resolve_destination, canonicalize_destination)
- case-only rename handling (
resolve_case_only_destination, relative_path_preserving_filename_case, plan_case_only_external_replacements)
- replacement planning for external refs, internal links, and directory moves (
plan_external_replacements, plan_internal_replacements, plan_directory_replacements, plus all the build_*_replacement helpers and line-cache bookkeeping)
- file rewriting and line-ending preservation (
apply_replacements, split_lines_preserving_endings, LineEnding)
- transactional execution with rollback (
execute_with_rollback, try_rename_regular_file{,_with}, RegularFileMoveMethod)
- preview / dry-run reporting (
build_move_preview, print_dry_run_report)
Even when the logic is correct, this layout makes every future bug fix or review noticeably more expensive.
Target State
Split src/core/mv.rs into a module directory organized by responsibility, keeping the public API (pub fn mv, pub fn preview_move) and observable behavior completely unchanged:
src/core/mv/
├── mod.rs # public entry points (mv / preview_move) + regular/case_only/directory orchestration
├── validate.rs # path resolution and validation
├── case_only.rs # case-only rename detection + planning
├── plan.rs # ReplacementPlan, all plan_*/build_*_replacement helpers, line cache
├── apply.rs # apply_replacements, line-ending preservation, rename fallback, execute_with_rollback
└── preview.rs # build_move_preview, print_dry_run_report
Transaction data model (MoveTransaction) already lives in src/core/model/move_transaction.rs and is reused as-is — no new transaction module is introduced.
Rationale
Concrete pain points today:
- Reading the file end-to-end is required to understand any single flow (regular move vs case-only rename vs directory move), because the three orchestrators and all their helpers are interleaved.
- The
mod tests block at the end of the file is already internally sectioned by comments (apply_replacements tests, build_link_replacement tests, etc.), which is a direct signal that the production code wants the same seams.
- Any future change to, for example, line-ending handling, has to be reviewed against unrelated planning code in the same diff.
Splitting by responsibility — not by "file size" — keeps each concern reviewable on its own and lets later stages layer small local abstractions safely.
Scope
mv
Current State
src/core/mv.rsis ~1750 lines and is the heaviest core file in the repo. It mixes at least six concerns in one module:validate_move_paths,resolve_destination,canonicalize_destination)resolve_case_only_destination,relative_path_preserving_filename_case,plan_case_only_external_replacements)plan_external_replacements,plan_internal_replacements,plan_directory_replacements, plus all thebuild_*_replacementhelpers and line-cache bookkeeping)apply_replacements,split_lines_preserving_endings,LineEnding)execute_with_rollback,try_rename_regular_file{,_with},RegularFileMoveMethod)build_move_preview,print_dry_run_report)Even when the logic is correct, this layout makes every future bug fix or review noticeably more expensive.
Target State
Split
src/core/mv.rsinto a module directory organized by responsibility, keeping the public API (pub fn mv,pub fn preview_move) and observable behavior completely unchanged:Transaction data model (
MoveTransaction) already lives insrc/core/model/move_transaction.rsand is reused as-is — no new transaction module is introduced.Rationale
Concrete pain points today:
mod testsblock at the end of the file is already internally sectioned by comments (apply_replacements tests,build_link_replacement tests, etc.), which is a direct signal that the production code wants the same seams.Splitting by responsibility — not by "file size" — keeps each concern reviewable on its own and lets later stages layer small local abstractions safely.
Scope
mv