From 4541e44f3a48cc7a5da5a06c033e1b1bfc36db46 Mon Sep 17 00:00:00 2001 From: Mika Vilpas Date: Wed, 22 May 2024 17:31:51 +0300 Subject: [PATCH] feat: allow yazi_closed_successfully hook to know the last yazi dir related: https://github.com/mikavilpas/yazi.nvim/issues/83 --- lua/yazi.lua | 29 ++++++++++++++++++++--------- lua/yazi/event_handling.lua | 12 ++++++++++++ lua/yazi/types.lua | 13 +++++++++++-- lua/yazi/utils.lua | 28 ++++++++++++++++++++++++---- tests/yazi/open_dir_spec.lua | 2 +- tests/yazi/yazi_spec.lua | 10 ++++++---- 6 files changed, 74 insertions(+), 20 deletions(-) diff --git a/lua/yazi.lua b/lua/yazi.lua index c96f5c1b..4e832303 100644 --- a/lua/yazi.lua +++ b/lua/yazi.lua @@ -10,9 +10,9 @@ local M = {} M.yazi_loaded = false ---@param config? YaziConfig? ----@param path? string +---@param input_path? string ---@diagnostic disable-next-line: redefined-local -function M.yazi(config, path) +function M.yazi(config, input_path) if utils.is_yazi_available() ~= true then print('Please install yazi. Check documentation for more information') return @@ -21,7 +21,7 @@ function M.yazi(config, path) config = vim.tbl_deep_extend('force', configModule.default(), M.config, config or {}) - path = utils.selected_file_path(path) + local path = utils.selected_file_path(input_path) local prev_win = vim.api.nvim_get_current_win() @@ -33,8 +33,8 @@ function M.yazi(config, path) os.remove(config.chosen_file_path) local cmd = string.format( - 'yazi %s --local-events "rename,delete,trash,move" --chooser-file "%s" > "%s"', - vim.fn.shellescape(path), + 'yazi %s --local-events "rename,delete,trash,move,cd" --chooser-file "%s" > "%s"', + vim.fn.shellescape(path.filename), config.chosen_file_path, config.events_file_path ) @@ -53,14 +53,25 @@ function M.yazi(config, path) return end - utils.on_yazi_exited(prev_win, win, config) - local events = utils.read_events_file(config.events_file_path) - event_handling.process_events_emitted_from_yazi(events) + local event_info = + 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, win, config, { + last_directory = event_info.last_directory or path:parent(), + }) end, }) - config.hooks.yazi_opened(path, win.content_buffer, config) + config.hooks.yazi_opened(path.filename, win.content_buffer, config) config.set_keymappings_function(win.content_buffer, config) win.on_resized = function(event) vim.fn.jobresize(job_id, event.win_width, event.win_height) diff --git a/lua/yazi/event_handling.lua b/lua/yazi/event_handling.lua index 92cd7922..22361e12 100644 --- a/lua/yazi/event_handling.lua +++ b/lua/yazi/event_handling.lua @@ -1,5 +1,6 @@ local utils = require('yazi.utils') local plenaryIterators = require('plenary.iterators') +local plenary_path = require('plenary.path') local lsp_delete = require('yazi.lsp.delete') local lsp_rename = require('yazi.lsp.rename') @@ -58,9 +59,13 @@ function M.get_buffers_that_need_renaming_after_yazi_exited( end ---@param events YaziEvent[] +---@return {last_directory?: Path} function M.process_events_emitted_from_yazi(events) -- process events emitted from yazi + ---@type Path | nil + local last_directory = nil + for i, event in ipairs(events) do if event.type == 'rename' then ---@cast event YaziRenameEvent @@ -91,8 +96,15 @@ function M.process_events_emitted_from_yazi(events) local remaining_events = vim.list_slice(events, i) ---@cast event YaziTrashEvent M.process_delete_event(event, remaining_events) + elseif event.type == 'cd' then + ---@cast event YaziChangeDirectoryEvent + if event.url ~= nil and event.url ~= '' then + last_directory = plenary_path:new(event.url) + end end end + + return { last_directory = last_directory } end return M diff --git a/lua/yazi/types.lua b/lua/yazi/types.lua index 2c24f899..d21a200b 100644 --- a/lua/yazi/types.lua +++ b/lua/yazi/types.lua @@ -13,10 +13,13 @@ ---@class YaziConfigHooks ---@field public yazi_opened fun(preselected_path: string | nil, buffer: integer, config: YaziConfig):nil ----@field public yazi_closed_successfully fun(chosen_file: string | nil, config: YaziConfig): nil +---@field public yazi_closed_successfully fun(chosen_file: string | nil, config: YaziConfig, state: YaziClosedState): nil ---@field public yazi_opened_multiple_files fun(chosen_files: string[], config: YaziConfig): nil ----@alias YaziEvent YaziRenameEvent | YaziMoveEvent | YaziDeleteEvent | YaziTrashEvent +---@alias YaziEvent YaziRenameEvent | YaziMoveEvent | YaziDeleteEvent | YaziTrashEvent | YaziChangeDirectoryEvent + +---@class YaziClosedState # describes the state of yazi when it was closed; the last known state +---@field public last_directory Path # the last directory that yazi was in before it was closed ---@class YaziRenameEvent ---@field public type "rename" @@ -46,6 +49,12 @@ ---@field public id string ---@field public data {urls: string[]} +---@class YaziChangeDirectoryEvent +---@field public type "cd" +---@field public timestamp string +---@field public id string +---@field public url string + ---@class yazi.AutoCmdEvent # the nvim_create_autocmd() event object copied from the nvim help docs ---@field public id number ---@field public event string diff --git a/lua/yazi/utils.lua b/lua/yazi/utils.lua index 3ecac23d..9eb2232d 100644 --- a/lua/yazi/utils.lua +++ b/lua/yazi/utils.lua @@ -1,5 +1,6 @@ local fn = vim.fn local RenameableBuffer = require('yazi.renameable_buffer') +local plenary_path = require('plenary.path') local M = {} @@ -19,7 +20,7 @@ function M.file_exists(name) end ---@param path string? ----@return string +---@return Path function M.selected_file_path(path) if path == '' or path == nil then path = vim.fn.expand('%:p') @@ -31,7 +32,7 @@ function M.selected_file_path(path) path = vim.fn.expand('%:p') end - return path + return plenary_path:new(path) end -- Returns parsed events from the yazi events file @@ -109,6 +110,22 @@ function M.parse_events(events_file_lines) data = vim.fn.json_decode(data_string), } table.insert(events, event) + elseif type == 'cd' then + -- example of a change directory (cd) event: + -- cd,1716307611001689,1716307611001689,{"tab":0,"url":"/tmp/test-directory"} + + local timestamp = parts[2] + local id = parts[3] + local data_string = table.concat(parts, ',', 4, #parts) + + ---@type YaziChangeDirectoryEvent + local event = { + type = type, + timestamp = timestamp, + id = id, + url = vim.fn.json_decode(data_string)['url'], + } + table.insert(events, event) end end @@ -177,7 +194,8 @@ end ---@param prev_win integer ---@param window YaziFloatingWindow ---@param config YaziConfig -function M.on_yazi_exited(prev_win, window, config) +---@param state YaziClosedState +function M.on_yazi_exited(prev_win, window, config, state) vim.cmd('silent! :checktime') -- open the file that was chosen @@ -195,11 +213,13 @@ function M.on_yazi_exited(prev_win, window, config) config.hooks.yazi_opened_multiple_files(chosen_files, config) else local chosen_file = chosen_files[1] - config.hooks.yazi_closed_successfully(chosen_file, config) + config.hooks.yazi_closed_successfully(chosen_file, config, state) if chosen_file then config.open_file_function(chosen_file, config) end end + else + config.hooks.yazi_closed_successfully(nil, config, state) end end diff --git a/tests/yazi/open_dir_spec.lua b/tests/yazi/open_dir_spec.lua index 3c1600c1..a7283099 100644 --- a/tests/yazi/open_dir_spec.lua +++ b/tests/yazi/open_dir_spec.lua @@ -25,7 +25,7 @@ describe('when the user set open_for_directories = true', function() vim.api.nvim_command('edit /') assert.stub(api_mock.termopen).was_called_with( - 'yazi \'/\' --local-events "rename,delete,trash,move" --chooser-file "/tmp/yazi_filechosen" > "/tmp/yazi.nvim.events.txt"', + 'yazi \'/\' --local-events "rename,delete,trash,move,cd" --chooser-file "/tmp/yazi_filechosen" > "/tmp/yazi.nvim.events.txt"', match.is_table() ) end) diff --git a/tests/yazi/yazi_spec.lua b/tests/yazi/yazi_spec.lua index 306da09a..39c1a29d 100644 --- a/tests/yazi/yazi_spec.lua +++ b/tests/yazi/yazi_spec.lua @@ -42,7 +42,7 @@ describe('opening a file', function() }) assert.stub(api_mock.termopen).was_called_with( - 'yazi \'/abc/test file-$1.txt\' --local-events "rename,delete,trash,move" --chooser-file "/tmp/yazi_filechosen" > "/tmp/yazi.nvim.events.txt"', + 'yazi \'/abc/test file-$1.txt\' --local-events "rename,delete,trash,move,cd" --chooser-file "/tmp/yazi_filechosen" > "/tmp/yazi.nvim.events.txt"', match.is_table() ) end) @@ -56,7 +56,7 @@ describe('opening a file', function() }) assert.stub(api_mock.termopen).was_called_with( - 'yazi \'/tmp/\' --local-events "rename,delete,trash,move" --chooser-file "/tmp/yazi_filechosen" > "/tmp/yazi.nvim.events.txt"', + 'yazi \'/tmp/\' --local-events "rename,delete,trash,move,cd" --chooser-file "/tmp/yazi_filechosen" > "/tmp/yazi.nvim.events.txt"', match.is_table() ) end) @@ -92,8 +92,10 @@ describe('opening a file', function() function() local target_file = '/abc/test-file-potato.txt' setup_fake_yazi_opens_file(target_file) - local spy_hook = spy.new(function(chosen_file) + ---@param state YaziClosedState + local spy_hook = spy.new(function(chosen_file, _config, state) assert.equals('/abc/test-file-potato.txt', chosen_file) + assert.equals('/abc', state.last_directory.filename) end) vim.api.nvim_command('edit /abc/test-file.txt') @@ -110,7 +112,7 @@ describe('opening a file', function() assert .spy(spy_hook) - .was_called_with('/abc/test-file-potato.txt', match.is_table()) + .was_called_with('/abc/test-file-potato.txt', match.is_table(), match.is_table()) end )