Skip to content

Commit 0904cdd

Browse files
committed
feat: when files are moved in yazi, they stay in sync in nvim
sxyazi/yazi#880
1 parent 77ed04d commit 0904cdd

File tree

8 files changed

+121
-11
lines changed

8 files changed

+121
-11
lines changed

lua/yazi.lua

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function M.yazi(config, path)
2828

2929
os.remove(config.chosen_file_path)
3030
local cmd = string.format(
31-
'yazi "%s" --local-events "rename,delete,trash" --chooser-file "%s" > %s',
31+
'yazi "%s" --local-events "rename,delete,trash,move" --chooser-file "%s" > %s',
3232
path,
3333
config.chosen_file_path,
3434
config.events_file_path
@@ -84,6 +84,20 @@ function M.yazi(config, path)
8484
instruction.path.filename
8585
)
8686
end
87+
elseif event.type == 'move' then
88+
---@cast event YaziMoveEvent
89+
for _, item in ipairs(event.data.items) do
90+
local rename_instructions =
91+
event_handling.get_buffers_that_need_renaming_after_yazi_exited(
92+
item
93+
)
94+
for _, instruction in ipairs(rename_instructions) do
95+
vim.api.nvim_buf_set_name(
96+
instruction.bufnr,
97+
instruction.path.filename
98+
)
99+
end
100+
end
87101
elseif event.type == 'delete' then
88102
---@cast event YaziDeleteEvent
89103
event_handling.process_delete_event(event)

lua/yazi/event_handling.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function M.process_delete_event(event)
1616
end
1717
end
1818

19-
---@param rename_event YaziEventDataRename
19+
---@param rename_event YaziEventDataRenameOrMove
2020
---@return RenameableBuffer[] "instructions for renaming the buffers (command pattern)"
2121
function M.get_buffers_that_need_renaming_after_yazi_exited(rename_event)
2222
local open_buffers = utils.get_open_buffers()

lua/yazi/types.lua

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,21 @@
1111
---@field public yazi_opened? fun(preselected_path: string | nil): nil
1212
---@field public yazi_closed_successfully? fun(chosen_file: string | nil): nil
1313

14-
---@alias YaziEvent YaziRenameEvent | YaziDeleteEvent | YaziTrashEvent
14+
---@alias YaziEvent YaziRenameEvent | YaziMoveEvent | YaziDeleteEvent | YaziTrashEvent
1515

1616
---@class YaziRenameEvent
1717
---@field public type "rename"
1818
---@field public timestamp string
1919
---@field public id string
20-
---@field public data YaziEventDataRename
20+
---@field public data YaziEventDataRenameOrMove
2121

22-
---@class YaziEventDataRename
22+
---@class YaziMoveEvent
23+
---@field public type "move"
24+
---@field public timestamp string
25+
---@field public id string
26+
---@field public data {items: YaziEventDataRenameOrMove[]}
27+
28+
---@class YaziEventDataRenameOrMove
2329
---@field public from string
2430
---@field public to string
2531

lua/yazi/utils.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,21 @@ function M.parse_events(events_file_lines)
6262
data = vim.fn.json_decode(data_string),
6363
}
6464
table.insert(events, event)
65+
elseif type == 'move' then
66+
-- example of a move event:
67+
-- move,1712854829131439,1712854829131439,{"items":[{"from":"/tmp/test/test","to":"/tmp/test"}]}
68+
local timestamp = parts[2]
69+
local id = parts[3]
70+
local data_string = table.concat(parts, ',', 4, #parts)
71+
72+
---@type YaziMoveEvent
73+
local event = {
74+
type = type,
75+
timestamp = timestamp,
76+
id = id,
77+
data = vim.fn.json_decode(data_string),
78+
}
79+
table.insert(events, event)
6580
elseif type == 'delete' then
6681
-- example of a delete event:
6782
-- delete,1712766606832135,1712766606832135,{"urls":["/tmp/test-directory/test_2"]}

tests/yazi/move_spec.lua

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
local assert = require('luassert')
2+
local event_handling = require('yazi.event_handling')
3+
4+
describe('get_buffers_that_need_renaming_after_yazi_exited', function()
5+
before_each(function()
6+
-- clear all buffers
7+
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
8+
vim.api.nvim_buf_delete(buf, { force = true })
9+
end
10+
end)
11+
12+
it('can detect moves to files whose names match exactly', function()
13+
---@type YaziEventDataRenameOrMove
14+
local move_event = {
15+
from = '/my-tmp/file1',
16+
to = '/my-tmp/file2',
17+
}
18+
19+
-- simulate buffers being opened
20+
vim.fn.bufadd('/my-tmp/file1')
21+
vim.fn.bufadd('/my-tmp/file_A')
22+
23+
local instructions =
24+
event_handling.get_buffers_that_need_renaming_after_yazi_exited(
25+
move_event
26+
)
27+
28+
assert.is_equal(vim.tbl_count(instructions), 1)
29+
30+
local result1 = instructions[1]
31+
assert.is_equal('/my-tmp/file2', result1.path.filename)
32+
assert.is_number(result1.bufnr)
33+
end)
34+
35+
it(
36+
'can detect moves to buffers open in a directory that was moved',
37+
function()
38+
---@type YaziEventDataRenameOrMove
39+
local move_event = {
40+
from = '/my-tmp/dir1',
41+
to = '/my-tmp/dir2',
42+
}
43+
44+
-- simulate the buffer being opened
45+
vim.fn.bufadd('/my-tmp/dir1/file')
46+
47+
local instructions =
48+
event_handling.get_buffers_that_need_renaming_after_yazi_exited(
49+
move_event
50+
)
51+
52+
assert.is_equal(vim.tbl_count(instructions), 1)
53+
local result = instructions[1]
54+
assert.is_equal('/my-tmp/dir2/file', result.path.filename)
55+
end
56+
)
57+
58+
it("doesn't move a buffer that was not moved in yazi", function()
59+
---@type YaziEventDataRenameOrMove
60+
local move_event = {
61+
from = '/my-tmp/not-opened-file',
62+
to = '/my-tmp/not-opened-file-moved',
63+
}
64+
65+
-- simulate the buffer being opened
66+
vim.fn.bufadd('/my-tmp/dir1/file')
67+
68+
local instructions =
69+
event_handling.get_buffers_that_need_renaming_after_yazi_exited(
70+
move_event
71+
)
72+
73+
assert.is_equal(vim.tbl_count(instructions), 0)
74+
end)
75+
end)

tests/yazi/open_dir_spec.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ describe('when the user set open_for_directories = true', function()
2121
vim.api.nvim_command('edit /')
2222

2323
assert.stub(api_mock.termopen).was_called_with(
24-
'yazi "/" --local-events "rename,delete,trash" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt',
24+
'yazi "/" --local-events "rename,delete,trash,move" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt',
2525
match.is_table()
2626
)
2727
end)

tests/yazi/rename_spec.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe('get_buffers_that_need_renaming_after_yazi_exited', function()
1010
end)
1111

1212
it('can detect renames to files whose names match exactly', function()
13-
---@type YaziEventDataRename
13+
---@type YaziEventDataRenameOrMove
1414
local rename_event = {
1515
from = '/my-tmp/file1',
1616
to = '/my-tmp/file2',
@@ -35,7 +35,7 @@ describe('get_buffers_that_need_renaming_after_yazi_exited', function()
3535
it(
3636
'can detect renames to buffers open in a directory that was renamed',
3737
function()
38-
---@type YaziEventDataRename
38+
---@type YaziEventDataRenameOrMove
3939
local rename_event = {
4040
from = '/my-tmp/dir1',
4141
to = '/my-tmp/dir2',
@@ -56,7 +56,7 @@ describe('get_buffers_that_need_renaming_after_yazi_exited', function()
5656
)
5757

5858
it("doesn't rename a buffer that was not renamed in yazi", function()
59-
---@type YaziEventDataRename
59+
---@type YaziEventDataRenameOrMove
6060
local rename_event = {
6161
from = '/my-tmp/not-opened-file',
6262
to = '/my-tmp/not-opened-file-renamed',

tests/yazi/yazi_spec.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ describe('opening a file', function()
1717
plugin.yazi()
1818

1919
assert.stub(api_mock.termopen).was_called_with(
20-
'yazi "/abc/test-file.txt" --local-events "rename,delete,trash" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt',
20+
'yazi "/abc/test-file.txt" --local-events "rename,delete,trash,move" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt',
2121
match.is_table()
2222
)
2323
end)
@@ -28,7 +28,7 @@ describe('opening a file', function()
2828
plugin.yazi()
2929

3030
assert.stub(api_mock.termopen).was_called_with(
31-
'yazi "/tmp/" --local-events "rename,delete,trash" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt',
31+
'yazi "/tmp/" --local-events "rename,delete,trash,move" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt',
3232
match.is_table()
3333
)
3434
end)

0 commit comments

Comments
 (0)