diff --git a/README.md b/README.md index 19555eb..2058ccb 100644 --- a/README.md +++ b/README.md @@ -120,12 +120,16 @@ or with lua ## Hooks You can provide hooks to perform additional actions on worktree addition, removal and switching + ```lua require('worktrees').setup { hooks = { on_add = function(name, path, branch) -- your action here end, + on_before_switch = function(from, to, git_path_info) + -- your action here + end, on_switch = function(from, to, git_path_info) -- your action here end, @@ -170,6 +174,44 @@ require('worktrees').setup { } ``` + +### Example - per-worktree sessions using `mini.sessions` + +```lua +require('worktrees').setup { + swap_current_buffer = false, + hooks = { + on_before_switch = function(from, to, git_path_info) + -- Persist worktree session before worktree switch. + MiniSessions.write(nil, { force = true, verbose = false }) + vim.cmd('silent! %bwipeout!') + + -- Prevent dangling LSP sessions. + vim.lsp.stop_client(vim.lsp.get_clients()) + + -- Out of the box, worktrees.nvim changes a working directory on worktree switch. + -- Optionally, you may prevent this by returning "false". + -- return false + end, + on_switch = function(from, to, git_path_info) + -- Restore session after worktree changes. + if vim.fn.filereadable(MiniSessions.config.file) then + MiniSessions.read(nil, { force = true, verbose = false }) + end + end, + on_before_remove = function(path) + if path ~= vim.loop.cwd() or vim.v.this_session == '' then + return + end + + -- Detach session if active worktree will be removed. + MiniSessions.delete(nil, { force = true, verbose = false }) + vim.v.this_session = '' + end + } +} +``` + ## Telescope The extension can be loaded with telescope @@ -226,4 +268,4 @@ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" ## TODO -- [ ] Options to customize behavior +- [ ] Options to customize behavior diff --git a/lua/worktrees/init.lua b/lua/worktrees/init.lua index 99f09f6..c032aba 100644 --- a/lua/worktrees/init.lua +++ b/lua/worktrees/init.lua @@ -3,9 +3,11 @@ local utils = require("worktrees.utils") local status = require("worktrees.status") ---@class worktrees.Hooks +---@field on_before_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo): boolean | nil ---@field on_switch fun(from: string, to: string, git_path_info: worktrees.GitPathInfo) ----@field on_add fun(name: string, path: string, branch: string) ----@field on_remove fun(name: string) +---@field on_add fun(name: string, path: string, branch: string) | nil +---@field on_before_remove fun(path: string) | nil +---@field on_remove fun(name: string) | nil ---@class worktrees.Options ---@field hooks? worktrees.Hooks, @@ -162,6 +164,20 @@ M.switch_worktree = function(path) end vim.schedule(function() + local prev_path = vim.loop.cwd() --[[@as string]] + + if M._options.hooks.on_before_switch then + -- on_before_switch can intercept worktree switch logic if returns 'false'. + local continue = M._options.hooks.on_before_switch( + prev_path, + found_path, + before_git_path_info + ) + if continue ~= nil and not continue then + return + end + end + -- Clear jumplist so that no file in the old worktree is present -- in the jumplist for accidental switching of worktrees vim.cmd("clearjumps") @@ -177,7 +193,6 @@ M.switch_worktree = function(path) -- Change neovim cwd if M._options.hooks.on_switch then - local prev_path = vim.loop.cwd() --[[@as string]] vim.cmd("cd " .. found_path) M._options.hooks.on_switch( prev_path, @@ -211,6 +226,10 @@ M.remove_worktree = function(path) return end + if M._options.hooks.on_before_remove then + M._options.hooks.on_before_remove(found_path) + end + if found_path == vim.loop.cwd() then local before_git_path_info = utils.get_git_path_info() if before_git_path_info == nil then