Move file into new directory by renaming #9
Labels
No labels
autorelease: pending
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
upstream/digest
upstream/pr
wontfix
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
barrettruth/canola.nvim#9
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Move a file into a new directory by including the directory name in the rename — e.g. changing
foo.txttonewdir/foo.txtcreatesnewdir/and moves the file into it. Multiple levels deep should work too:a/b/c/file.txt.Upstream context
stevearc/oil.nvim#117, #289, #675, #707, #708 — various reports of the same missing behaviour.
Root cause
There are two layers to the problem.
Layer 1 — parser rejects the edit. In
lua/oil/mutator/parser.lua, when parsing an existing entry (lines beginning with/ID), the parser checks whether the parsed name contains/and immediately errors withFilename cannot contain path separator. The user's edit never reaches the mutation pipeline.Layer 2 — even if it did, no intermediate dir would be created. When
diff.idis set (i.e. it is a rename of an existing entry),create_actions_from_diffsresolves it as a move toparent_url .. diff.name. It does not split the destination path to synthesisecreateactions for any intermediate directories. The path-splitting logic that does handle nested paths (lines 103–130 inmutator/init.lua) only runs for new entries (diff.id == nil).Proposed approach
Parser change
Remove the hard error for
/in an existing-entry name. Instead, treat it as a valid rename target. The parsed name is allowed to contain/in this context; the mutation pipeline must handle it.Two sub-cases arise:
newdir/file.txtwherenewdirdoes not yet exist) — synthesisecreate directory+moveactions.moveaction only.Mutator change
In
create_actions_from_diffs, when processing adiffwithdiff.idset (an existing-entry rename), check whetherdiff.namecontains a path separator. If it does:create directoryaction at the appropriate URL (same deduplication guard as for new entries already exists viaseen_creates).moveaction withdest_urlpointing to the full resolved path.The topological sort in
enforce_action_orderalready ensurescreateactions for parent directories are ordered before themovethat depends on them (dest_trie:accum_first_parents_ofhandles this for move actions), so no changes totrie.luaor the ordering logic are required.new_dir_modebehaviourThe
create directoryactions synthesised by a path-separator rename go through the normalperform_actionpath inadapters/files.lua, which already callsuv.fs_mkdir(path, config.new_dir_mode, ...). No special handling is needed; user-configurednew_dir_modeis respected automatically.Edge cases
a/b/c/file.txt): handled by splitting on/and emitting onecreateper segment, same as the existing new-entry logic.createaction will fail at the adapter level with a "file exists" error. This is the correct behaviour — the user should usenewdir/(trailing slash) to move into an existing directory.moveaction will overwrite it, consistent with existing move semantics.newdir/foo.txtis unique by that check even if another entry is namedfoo.txt. The real conflict check happens at the adapter level.enforce_action_orderoperates on full URLs, so movinga/btob/ais handled correctly regardless of whether intermediate directories are synthesised.perform_actionforcreateandmove. The synthesised actions use the same URL scheme as the buffer, so no adapter-specific changes are needed.Scope
newdir/file.txta/b/c/file.txtcreateactions for intermediate dirs are ordered before themoveImplemented in #222.