Skip to content

feat(files): drag-and-drop rename / move in the Files tree#35

Merged
danielss-dev merged 2 commits into
mainfrom
feat/file-tree-dnd-rename
Jul 6, 2026
Merged

feat(files): drag-and-drop rename / move in the Files tree#35
danielss-dev merged 2 commits into
mainfrom
feat/file-tree-dnd-rename

Conversation

@danielss-dev

Copy link
Copy Markdown
Owner

Summary

  • Repo::move_path (crates/strand-core/src/rename.rs): rename / move a working-tree entry. Tracked sources (any index entry at or under the path) shell out to git mv so the index entry moves with the file — staged content preserved, directory moves and case-only renames handled natively; untracked sources are a plain fs rename. Refuses to overwrite, creates missing destination parent dirs, and guards both ends (safe_workdir_path for the source, an ancestor-walking variant for the not-yet-existing destination).
  • repo_move_path IPC (quick sync write) + useRepo.moveEntries: sequential moves with a single snapshot refresh, per-entry failure strings so one collision does not hide the moves that succeeded; an open file view follows its file to the new path.
  • PierreTree drag-to-move (opt-in onMove): pointer-based — the rows live in Pierre's shadow root where nothing can be marked draggable, but mouse events compose across the boundary. All imperative refs + direct DOM so the 60Hz mousemove never re-renders the tree. 5px threshold, cursor-chasing ghost chip naming entry + target (dashed when invalid), --bg-sel wash on the hovered folder row, file rows target their containing folder, bare tree space the repo root, Escape cancels, a multi-selected file drags the whole selection.
  • RenameFileDialog behind the Files-tree context menu ("Rename / move…") for keyboard parity; filename segment preselected.
  • Docs: ROADMAP 1.0 items closed (drag-and-drop renames + the 100k-commit perf pass line, which the 0.5 perf close already satisfied), TASKS entries added.

Test plan

  • cargo test -p strand-core — 96 pass (+5 new rename tests: tracked/untracked/directory moves, overwrite + missing + no-op guards, traversal/absolute rejection)
  • cargo clippy --workspace --all-targets — no new warnings (4 pre-existing in commit.rs/history.rs test code from a newer clippy)
  • tsc --noEmit, vitest run (198 pass), vite build
  • End-to-end over WebView2 CDP against the running app: dragged a tracked root file into src/ (git status R rootfile.txt -> src/rootfile.txt), an untracked file into docs/ (stays untracked, index untouched), and dialog-renamed a modified file (RM with the worktree edit preserved); asserted the ghost chip text mid-drag and its removal after drop.

🤖 Generated with Claude Code

Repo::move_path (git mv for tracked sources, fs rename for untracked;
overwrite refused, dest parents created, both ends path-guarded) +
repo_move_path IPC + useRepo.moveEntries. PierreTree grows an opt-in
pointer-based drag (shadow-root rows cannot be draggable; mouse events
compose across the boundary) with a ghost chip, folder-row wash, and
Escape cancel; context-menu "Rename / move..." opens RenameFileDialog
for keyboard parity. Verified end-to-end over WebView2 CDP.
@danielss-dev danielss-dev merged commit d79a00b into main Jul 6, 2026
2 checks passed
@danielss-dev danielss-dev deleted the feat/file-tree-dnd-rename branch July 6, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant