Skip to content

Commit

Permalink
fix: report parent directory of input_path as last_directory
Browse files Browse the repository at this point in the history
Background
==========

When yazi is started too late, it can happen that we don't know what the
last_directory was when yazi has exited. This currently happens when `ya`
is started too late - yazi has already reported its `cd` event before `ya`
starts and yazi.nvim cannot capture it.

The issue can be tracked in sxyazi/yazi#1314

Issue
=====

Currently yazi.nvim works around this limitation by using the parent
directory of the input_path as the last_directory since it's a good guess.

However, it looks like this has never worked reliably due to a bug in the
implementation. The correct directory was calculated, but it was not
assigned to the last_directory field in the state - it was ignored and
had no effect.

Solution
========

Assign the correct directory to the last_directory field in the state.
  • Loading branch information
mikavilpas committed Oct 16, 2024
1 parent 5199400 commit 8ab332f
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 33 deletions.
4 changes: 3 additions & 1 deletion lua/yazi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,17 @@ function M.yazi(config, input_path)
yazi_event_handling.process_events_emitted_from_yazi(events)

local last_directory = event_info.last_directory

if last_directory == nil then
if path:is_file() then
last_directory = path:parent()
else
last_directory = path
end
end

utils.on_yazi_exited(prev_win, prev_buf, win, config, selected_files, {
last_directory = event_info.last_directory or path:parent(),
last_directory = last_directory,
})

if hovered_url then
Expand Down
17 changes: 17 additions & 0 deletions spec/yazi/helpers/test_files.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
local M = {}

---@param target_file string
function M.create_test_file(target_file)
local plenary_path = require("plenary.path")
local file = io.open(target_file, "w") -- Open or create the file in write mode
assert(file, "Failed to create file " .. target_file)
if file then
file:write("")
file:close()
end
assert(plenary_path:new(target_file):exists())
assert(plenary_path:new(target_file):is_file())
assert(plenary_path:new(target_file):parent():is_dir())
end

return M
124 changes: 92 additions & 32 deletions spec/yazi/yazi_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local assert = require("luassert")
local mock = require("luassert.mock")
local match = require("luassert.match")
local spy = require("luassert.spy")
local test_files = require("spec.yazi.helpers.test_files")
package.loaded["yazi.process.yazi_process"] =
require("spec.yazi.helpers.fake_yazi_process")
local fake_yazi_process = require("spec.yazi.helpers.fake_yazi_process")
Expand Down Expand Up @@ -68,38 +69,97 @@ describe("opening a file", function()
assert_opened_yazi_with_files({ "/tmp/" })
end)

it(
"calls the yazi_closed_successfully hook when a file is selected in yazi's chooser",
function()
local target_file = "/abc/test-file-potato.txt"

fake_yazi_process.setup_created_instances_to_instantly_exit({
selected_files = { target_file },
})

---@param state YaziClosedState
---@diagnostic disable-next-line: unused-local
local spy_hook = spy.new(function(chosen_file, _config, state)
assert.equals(target_file, chosen_file)
assert.equals("/abc", state.last_directory.filename)
end)

vim.api.nvim_command("edit /abc/test-file.txt")

plugin.yazi({
chosen_file_path = "/tmp/yazi_filechosen",
---@diagnostic disable-next-line: missing-fields
hooks = {
---@diagnostic disable-next-line: assign-type-mismatch
yazi_closed_successfully = spy_hook,
},
})

assert
.spy(spy_hook)
.was_called_with(target_file, match.is_table(), match.is_table())
end
)
describe("when a file is selected in yazi's chooser", function()
it(
"calls the yazi_closed_successfully hook with the target_file and last_directory",
function()
fake_yazi_process.setup_created_instances_to_instantly_exit({
selected_files = {
-- in this test, the cd event defines the last_directory so this is ignored
},
---@type YaziChangeDirectoryEvent[]
events = {
{
type = "cd",
timestamp = "123",
id = "123",
url = "/abc",
},
},
})

---@param state YaziClosedState
---@diagnostic disable-next-line: unused-local
local spy_hook = spy.new(function(chosen_file, _config, state)
assert.equals(nil, chosen_file)
assert.equals("/abc", state.last_directory.filename)
end)

plugin.yazi({
chosen_file_path = "/tmp/yazi_filechosen",
---@diagnostic disable-next-line: missing-fields
hooks = {
---@diagnostic disable-next-line: assign-type-mismatch
yazi_closed_successfully = spy_hook,
},
})

assert
.spy(spy_hook)
.was_called_with(nil, match.is_table(), match.is_table())
end
)

it(
"uses the parent directory of the input_path as the last_directory when no events are emitted",
function()
local plenary_path = require("plenary.path")
-- it can happen that we don't know what the last_directory was when
-- yazi has exited. This currently happens when `ya` is started too
-- late - yazi has already reported its `cd` event before `ya` starts
-- due to https://github.com/sxyazi/yazi/issues/1314
--
-- we work around this by using the parent directory of the input_path
-- since it's a good guess
local target_file =
"/tmp/test-file-potato-ea7142f8-ac6d-4037-882c-7dbc4f7b6c65.txt"
test_files.create_test_file(target_file)

fake_yazi_process.setup_created_instances_to_instantly_exit({
selected_files = { target_file },
events = {
-- no events are emitted from yazi
},
})

local spy_yazi_closed_successfully = spy.new(
---@param state YaziClosedState
---@diagnostic disable-next-line: unused-local
function(chosen_file, _config, state)
assert.equals(target_file, chosen_file)
assert.equals("/tmp", state.last_directory.filename)
assert.equals(
"/tmp",
plenary_path:new(target_file):parent().filename
)
end
)

plugin.yazi({
chosen_file_path = "/tmp/yazi_filechosen",
---@diagnostic disable-next-line: missing-fields
hooks = {
---@diagnostic disable-next-line: assign-type-mismatch
yazi_closed_successfully = spy_yazi_closed_successfully,
},
}, target_file)

assert
.spy(spy_yazi_closed_successfully)
.was_called_with(target_file, match.is_table(), match.is_table())
end
)
end)

it("calls the yazi_opened hook when yazi is opened", function()
local spy_yazi_opened_hook = spy.new()
Expand Down

0 comments on commit 8ab332f

Please sign in to comment.