From 9d7fdbb1a39b363b28faf636dadefe30e1dbde97 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Tue, 7 Nov 2023 16:39:07 -0500 Subject: [PATCH 01/33] feat: v2 refactor --- lua/git-worktree/git.lua | 169 ++++++++++++++++ lua/git-worktree/hooks.lua | 26 +++ lua/git-worktree/init.lua | 217 +++------------------ lua/telescope/_extensions/git_worktree.lua | 16 +- 4 files changed, 225 insertions(+), 203 deletions(-) create mode 100644 lua/git-worktree/git.lua create mode 100644 lua/git-worktree/hooks.lua diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua new file mode 100644 index 0000000..e9e342f --- /dev/null +++ b/lua/git-worktree/git.lua @@ -0,0 +1,169 @@ +local Job = require("plenary.job") +local Path = require("plenary.path") +local Status = require("git-worktree.status") + +local status = Status:new() + +---@class GitWorktreeGitOps +local M = {} + +--- @return boolean +function M.is_bare_repo() + local inside_worktree_job = Job:new({ + 'git', + 'rev-parse', + '--is-bare-repository', + cwd = vim.loop.cwd(), + }) + + local stdout, code = inside_worktree_job:sync() + if code ~= 0 then + status:log().error("Error in determining if we are in a worktree") + return false + end + + stdout = table.concat(stdout, "") + + if stdout == "true" then + return true + else + return false + end +end + +--- @return boolean +function M.is_worktree() + local inside_worktree_job = Job:new({ + 'git', + 'rev-parse', + '--is-inside-work-tree', + cwd = vim.loop.cwd(), + }) + + local stdout, code = inside_worktree_job:sync() + if code ~= 0 then + status:log().error("Error in determining if we are in a worktree") + return false + end + + stdout = table.concat(stdout, "") + + if stdout == "true" then + return true + else + return false + end +end + +--- @param is_worktree boolean +--- @return string|nil +function M.find_git_dir(is_worktree) + local find_git_dir_job = Job:new({ + 'git', + 'rev-parse', + '--absolute-git-dir', + cwd = vim.loop.cwd(), + }) + + local stdout, code = find_git_dir_job:sync() + if code ~= 0 then + status:log().error("Error in determining the git root dir") + return nil + end + + stdout = table.concat(stdout, "") + + if is_worktree then + -- if in worktree git dir returns absolute path + + -- try to find the dot git folder (non-bare repo) + local git_dir = Path:new(stdout) + local has_dot_git = false + for _, dir in ipairs(git_dir:_split()) do + if dir == ".git" then + has_dot_git = true + break + end + end + + if has_dot_git then + if stdout == ".git" then + return vim.loop.cwd() + else + local start = stdout:find("%.git") + return stdout:sub(1, start - 2) + end + else + local start = stdout:find("/worktrees/") + return stdout:sub(0, start - 1) + end + elseif stdout == "." then + -- we are in the root git dir + return vim.loop.cwd() + else + -- if not in worktree git dir should be absolute + return stdout + end +end + +--- @return string|nil +function M.find_git_toplevel() + local find_toplevel_job = Job:new({ + 'git', + 'rev-parse', + '--show-toplevel', + cwd = cwd, + }) + local stdout, code = find_toplevel_job:sync() + if code == 0 then + stdout = table.concat(stdout, "") + return stdout + else + return nil + end +end + +function M.has_branch(branch, cb) + local found = false + local job = Job:new({ + 'git', + 'branch', + on_stdout = function(_, data) + -- remove markere on current branch + data = data:gsub("*", "") + data = vim.trim(data) + found = found or data == branch + end, + cwd = vim.loop.cwd(), + }) + + -- TODO: I really don't want status's spread everywhere... seems bad + status:next_status(string.format("Checking for branch %s", branch)) + job:after(function() + status:status("found branch: " .. tostring(found)) + cb(found) + end):start() +end + +function M.has_origin() + local found = false + local job = Job:new({ + 'git', + 'remote', + 'show', + on_stdout = function(_, data) + data = vim.trim(data) + found = found or data == 'origin' + end, + cwd = vim.loop.cwd(), + }) + + -- TODO: I really don't want status's spread everywhere... seems bad + job:after(function() + status:status("found origin: " .. tostring(found)) + end):sync() + + return found +end + +return M diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua new file mode 100644 index 0000000..70980bb --- /dev/null +++ b/lua/git-worktree/hooks.lua @@ -0,0 +1,26 @@ +--- @class GitWorktreeHooks +local M = {} + +local function on_tree_change_handler(op, metadata) + if M._config.update_on_change then + if op == Enum.Operations.Switch then + local changed = M.update_current_buffer(metadata["prev_path"]) + if not changed then + status:log().debug( + "Could not change to the file in the new worktree, running the `update_on_change_command`") + vim.cmd(M._config.update_on_change_command) + end + end + end +end + +local function emit_on_change(op, metadata) + -- TODO: We don't have a way to async update what is running + status:next_status(string.format("Running post %s callbacks", op)) + on_tree_change_handler(op, metadata) + for idx = 1, #on_change_callbacks do + on_change_callbacks[idx](op, metadata) + end +end + +return M diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index 0fb5295..79d387c 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -10,140 +10,6 @@ local git_worktree_root = nil local current_worktree_path = nil local on_change_callbacks = {} -M.setup_git_info = function() - local cwd = vim.loop.cwd() - - local is_in_worktree = false - - local inside_worktree_job = Job:new({ - 'git', 'rev-parse', '--is-inside-work-tree', - cwd = cwd, - }) - - local process_inside_worktree = function(stdout) - if stdout == "true" then - is_in_worktree = true - end - end - - local find_git_dir_job = Job:new({ - 'git', 'rev-parse', '--absolute-git-dir', - cwd = cwd, - }) - - local process_find_git_dir = function(stdout) - if is_in_worktree then - -- if in worktree git dir returns absolute path - - -- try to find the dot git folder (non-bare repo) - local git_dir = Path:new(stdout) - local has_dot_git = false - for _, dir in ipairs(git_dir:_split()) do - if dir == ".git" then - has_dot_git = true - break - end - end - - if has_dot_git then - if stdout == ".git" then - git_worktree_root = cwd - else - local start = stdout:find("%.git") - git_worktree_root = stdout:sub(1,start - 2) - end - else - local start = stdout:find("/worktrees/") - git_worktree_root = stdout:sub(0, start - 1) - end - elseif stdout == "." then - -- we are in the root git dir - git_worktree_root = cwd - else - -- if not in worktree git dir should be absolute - git_worktree_root = stdout - end - status:log():debug("git directory is: " .. git_worktree_root) - end - - local find_toplevel_job = Job:new({ - 'git', 'rev-parse', '--show-toplevel', - cwd = cwd, - }) - - local find_toplevel_bare_job = Job:new({ - 'git', 'rev-parse', '--is-bare-repository', - cwd = cwd, - }) - - local process_find_toplevel = function(stdout) - current_worktree_path = stdout - status:log().debug("git toplevel is: " .. current_worktree_path) - end - - local process_find_toplevel_bare = function(stdout) - if stdout == "true" then - current_worktree_path = cwd - end - end - - local stdout, code = inside_worktree_job:sync() - if code ~= 0 then - status:log().error("Error in determining if we are in a worktree") - git_worktree_root = nil - current_worktree_path = nil - return - end - stdout = table.concat(stdout, "") - process_inside_worktree(stdout) - - stdout, code = find_git_dir_job:sync() - if code ~= 0 then - status:log().error("Error in determining the git root dir") - git_worktree_root = nil - return - end - stdout = table.concat(stdout, "") - process_find_git_dir(stdout) - - stdout, code = find_toplevel_job:sync() - if code == 0 then - stdout = table.concat(stdout, "") - process_find_toplevel(stdout) - else - stdout, code = find_toplevel_bare_job:sync() - if code == 0 then - stdout = table.concat(stdout, "") - process_find_toplevel_bare(stdout) - else - status:log().error("Error in determining the git toplevel") - current_worktree_path = nil - return - end - end - -end - -local function on_tree_change_handler(op, metadata) - if M._config.update_on_change then - if op == Enum.Operations.Switch then - local changed = M.update_current_buffer(metadata["prev_path"]) - if not changed then - status:log().debug("Could not change to the file in the new worktree, running the `update_on_change_command`") - vim.cmd(M._config.update_on_change_command) - end - end - end -end - -local function emit_on_change(op, metadata) - -- TODO: We don't have a way to async update what is running - status:next_status(string.format("Running post %s callbacks", op)) - on_tree_change_handler(op, metadata) - for idx = 1, #on_change_callbacks do - on_change_callbacks[idx](op, metadata) - end -end local function change_dirs(path) local worktree_path = M.get_worktree_path(path) @@ -157,7 +23,7 @@ local function change_dirs(path) vim.cmd(cmd) current_worktree_path = worktree_path else - status:error('Could not chang to directory: ' ..worktree_path) + status:error('Could not chang to directory: ' .. worktree_path) end if M._config.clearjumps_on_change then @@ -169,9 +35,8 @@ local function change_dirs(path) end local function create_worktree_job(path, branch, found_branch) - local worktree_add_cmd = 'git' - local worktree_add_args = {'worktree', 'add'} + local worktree_add_args = { 'worktree', 'add' } if not found_branch then table.insert(worktree_add_args, '-b') @@ -199,8 +64,10 @@ local function has_worktree(path, cb) local plenary_path = Path:new(path) local job = Job:new({ - 'git', 'worktree', 'list', on_stdout = function(_, data) - + 'git', + 'worktree', + 'list', + on_stdout = function(_, data) local list_data = {} for section in data:gmatch("%S+") do table.insert(list_data, section) @@ -253,44 +120,7 @@ local function failure(from, cmd, path, soft_error) end end -local function has_origin() - local found = false - local job = Job:new({ - 'git', 'remote', 'show', - on_stdout = function(_, data) - data = vim.trim(data) - found = found or data == 'origin' - end, - cwd = git_worktree_root, - }) - - -- TODO: I really don't want status's spread everywhere... seems bad - job:after(function() - status:status("found origin: " .. tostring(found)) - end):sync() - - return found -end - -local function has_branch(branch, cb) - local found = false - local job = Job:new({ - 'git', 'branch', on_stdout = function(_, data) - -- remove markere on current branch - data = data:gsub("*","") - data = vim.trim(data) - found = found or data == branch - end, - cwd = git_worktree_root, - }) - -- TODO: I really don't want status's spread everywhere... seems bad - status:next_status(string.format("Checking for branch %s", branch)) - job:after(function() - status:status("found branch: " .. tostring(found)) - cb(found) - end):start() -end local function create_worktree(path, branch, upstream, found_branch) local create = create_worktree_job(path, branch, found_branch) @@ -302,17 +132,19 @@ local function create_worktree(path, branch, upstream, found_branch) worktree_path = Path:new(git_worktree_root, path):absolute() end - local fetch = Job:new({ - 'git', 'fetch', '--all', + local fetch = Job:new({ + 'git', + 'fetch', + '--all', cwd = worktree_path, on_start = function() status:next_status("git fetch --all (This may take a moment)") end }) - local set_branch_cmd = 'git' - local set_branch_args= {'branch', string.format('--set-upstream-to=%s/%s', upstream, branch)} - local set_branch = Job:new({ + local set_branch_cmd = 'git' + local set_branch_args = { 'branch', string.format('--set-upstream-to=%s/%s', upstream, branch) } + local set_branch = Job:new({ command = set_branch_cmd, args = set_branch_args, cwd = worktree_path, @@ -323,9 +155,9 @@ local function create_worktree(path, branch, upstream, found_branch) -- TODO: How to configure origin??? Should upstream ever be the push -- destination? - local set_push_cmd = 'git' - local set_push_args = {'push', "--set-upstream", upstream, branch, path} - local set_push = Job:new({ + local set_push_cmd = 'git' + local set_push_args = { 'push', "--set-upstream", upstream, branch, path } + local set_push = Job:new({ command = set_push_cmd, args = set_push_args, cwd = worktree_path, @@ -334,8 +166,9 @@ local function create_worktree(path, branch, upstream, found_branch) end }) - local rebase = Job:new({ - 'git', 'rebase', + local rebase = Job:new({ + 'git', + 'rebase', cwd = worktree_path, on_start = function() status:next_status("git rebase") @@ -362,20 +195,19 @@ local function create_worktree(path, branch, upstream, found_branch) set_branch:after_failure(failure("create_worktree", set_branch.args, worktree_path, true)) rebase:after(function() - if rebase.code ~= 0 then status:status("Rebase failed, but that's ok.") end vim.schedule(function() - emit_on_change(Enum.Operations.Create, {path = path, branch = branch, upstream = upstream}) + emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) M.switch_worktree(path) end) end) else create:after(function() vim.schedule(function() - emit_on_change(Enum.Operations.Create, {path = path, branch = branch, upstream = upstream}) + emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) M.switch_worktree(path) end) end) @@ -404,14 +236,12 @@ M.create_worktree = function(path, branch, upstream) create_worktree(path, branch, upstream, found_branch) end) end) - end M.switch_worktree = function(path) status:reset(2) M.setup_git_info() has_worktree(path, function(found) - if not found then status:error("worktree does not exists, please create it first " .. path) end @@ -420,7 +250,6 @@ M.switch_worktree = function(path) local prev_path = change_dirs(path) emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) end) - end) end @@ -485,7 +314,7 @@ M.update_current_buffer = function(prev_path) end local name = Path:new(current_buf_name):absolute() - local start, fin = string.find(name, cwd..Path.path.sep, 1, true) + local start, fin = string.find(name, cwd .. Path.path.sep, 1, true) if start ~= nil then return true end @@ -497,7 +326,7 @@ M.update_current_buffer = function(prev_path) local local_name = name:sub(fin + 2) - local final_path = Path:new({cwd, local_name}):absolute() + local final_path = Path:new({ cwd, local_name }):absolute() if not Path:new(final_path):exists() then return false diff --git a/lua/telescope/_extensions/git_worktree.lua b/lua/telescope/_extensions/git_worktree.lua index 706cd2b..96c2b33 100644 --- a/lua/telescope/_extensions/git_worktree.lua +++ b/lua/telescope/_extensions/git_worktree.lua @@ -76,15 +76,14 @@ local delete_worktree = function(prompt_bufnr) local worktree_path = get_worktree_path(prompt_bufnr) actions.close(prompt_bufnr) if worktree_path ~= nil then - git_worktree.delete_worktree(worktree_path, force_next_deletion, { - on_failure = delete_failure_handler, - on_success = delete_success_handler - }) + git_worktree.delete_worktree(worktree_path, force_next_deletion, { + on_failure = delete_failure_handler, + on_success = delete_success_handler + }) end end local create_input_prompt = function(cb) - --[[ local window = Window.centered({ width = 30, @@ -143,7 +142,7 @@ end local telescope_git_worktree = function(opts) opts = opts or {} - local output = utils.get_os_command_output({"git", "worktree", "list"}) + local output = utils.get_os_command_output({ "git", "worktree", "list" }) local results = {} local widths = { path = 0, @@ -194,7 +193,7 @@ local telescope_git_worktree = function(opts) local make_display = function(entry) return displayer { - { entry.branch, "TelescopeResultsIdentifier" }, + { entry.branch, "TelescopeResultsIdentifier" }, { utils.transform_path(opts, entry.path) }, { entry.sha }, } @@ -226,10 +225,9 @@ local telescope_git_worktree = function(opts) end return require("telescope").register_extension( - { + { exports = { git_worktree = telescope_git_worktree, - git_worktrees = telescope_git_worktree, create_git_worktree = create_worktree } }) From a43c4ac22f61cf5567236a22558932e718b101a8 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 8 Nov 2023 11:40:30 -0500 Subject: [PATCH 02/33] chore: mv test repo to spec dir --- .../.repo}/.git-orig/COMMIT_EDITMSG | 0 .../repo_origin => spec/.repo}/.git-orig/FETCH_HEAD | 0 {tests/repo_origin => spec/.repo}/.git-orig/HEAD | 0 {tests/repo_origin => spec/.repo}/.git-orig/config | 0 .../.repo}/.git-orig/description | 0 .../.repo}/.git-orig/hooks/applypatch-msg.sample | 0 .../.repo}/.git-orig/hooks/commit-msg.sample | 0 .../.git-orig/hooks/fsmonitor-watchman.sample | 0 .../.repo}/.git-orig/hooks/post-update.sample | 0 .../.repo}/.git-orig/hooks/pre-applypatch.sample | 0 .../.repo}/.git-orig/hooks/pre-commit.sample | 0 .../.repo}/.git-orig/hooks/pre-merge-commit.sample | 0 .../.repo}/.git-orig/hooks/pre-push.sample | 0 .../.repo}/.git-orig/hooks/pre-rebase.sample | 0 .../.repo}/.git-orig/hooks/pre-receive.sample | 0 .../.git-orig/hooks/prepare-commit-msg.sample | 0 .../.repo}/.git-orig/hooks/update.sample | 0 {tests/repo_origin => spec/.repo}/.git-orig/index | Bin .../.repo}/.git-orig/info/exclude | 0 .../repo_origin => spec/.repo}/.git-orig/logs/HEAD | 0 .../.repo}/.git-orig/logs/refs/heads/featB | 0 .../.repo}/.git-orig/logs/refs/heads/featC | 0 .../.repo}/.git-orig/logs/refs/heads/master | 0 .../0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 | Bin .../1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 | Bin .../2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 | 0 .../30/a0f033a755629a8ef1561e7b7ece3750ce8a13 | Bin .../39/ba5d897e269fb97a17058423947603f010e702 | Bin .../3b/73d17c51c9b22ff9d4552e5bb56927776173b3 | Bin .../40/c09bafbe2555af7017dd08f027e4ae45db2879 | Bin .../61/fcdbfa0b2af3418651b55d003c05c8e128d22e | Bin .../91/b5884361b690f3bf1ba2edc9145a01d651a920 | Bin .../.repo}/.git-orig/refs/heads/featB | 0 .../.repo}/.git-orig/refs/heads/featC | 0 .../.repo}/.git-orig/refs/heads/master | 0 {tests/repo_origin => spec/.repo}/A.txt | 0 36 files changed, 0 insertions(+), 0 deletions(-) rename {tests/repo_origin => spec/.repo}/.git-orig/COMMIT_EDITMSG (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/FETCH_HEAD (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/HEAD (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/config (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/description (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/applypatch-msg.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/commit-msg.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/fsmonitor-watchman.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/post-update.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/pre-applypatch.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/pre-commit.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/pre-merge-commit.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/pre-push.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/pre-rebase.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/pre-receive.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/prepare-commit-msg.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/hooks/update.sample (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/index (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/info/exclude (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/logs/HEAD (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/logs/refs/heads/featB (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/logs/refs/heads/featC (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/logs/refs/heads/master (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/refs/heads/featB (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/refs/heads/featC (100%) rename {tests/repo_origin => spec/.repo}/.git-orig/refs/heads/master (100%) rename {tests/repo_origin => spec/.repo}/A.txt (100%) diff --git a/tests/repo_origin/.git-orig/COMMIT_EDITMSG b/spec/.repo/.git-orig/COMMIT_EDITMSG similarity index 100% rename from tests/repo_origin/.git-orig/COMMIT_EDITMSG rename to spec/.repo/.git-orig/COMMIT_EDITMSG diff --git a/tests/repo_origin/.git-orig/FETCH_HEAD b/spec/.repo/.git-orig/FETCH_HEAD similarity index 100% rename from tests/repo_origin/.git-orig/FETCH_HEAD rename to spec/.repo/.git-orig/FETCH_HEAD diff --git a/tests/repo_origin/.git-orig/HEAD b/spec/.repo/.git-orig/HEAD similarity index 100% rename from tests/repo_origin/.git-orig/HEAD rename to spec/.repo/.git-orig/HEAD diff --git a/tests/repo_origin/.git-orig/config b/spec/.repo/.git-orig/config similarity index 100% rename from tests/repo_origin/.git-orig/config rename to spec/.repo/.git-orig/config diff --git a/tests/repo_origin/.git-orig/description b/spec/.repo/.git-orig/description similarity index 100% rename from tests/repo_origin/.git-orig/description rename to spec/.repo/.git-orig/description diff --git a/tests/repo_origin/.git-orig/hooks/applypatch-msg.sample b/spec/.repo/.git-orig/hooks/applypatch-msg.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/applypatch-msg.sample rename to spec/.repo/.git-orig/hooks/applypatch-msg.sample diff --git a/tests/repo_origin/.git-orig/hooks/commit-msg.sample b/spec/.repo/.git-orig/hooks/commit-msg.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/commit-msg.sample rename to spec/.repo/.git-orig/hooks/commit-msg.sample diff --git a/tests/repo_origin/.git-orig/hooks/fsmonitor-watchman.sample b/spec/.repo/.git-orig/hooks/fsmonitor-watchman.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/fsmonitor-watchman.sample rename to spec/.repo/.git-orig/hooks/fsmonitor-watchman.sample diff --git a/tests/repo_origin/.git-orig/hooks/post-update.sample b/spec/.repo/.git-orig/hooks/post-update.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/post-update.sample rename to spec/.repo/.git-orig/hooks/post-update.sample diff --git a/tests/repo_origin/.git-orig/hooks/pre-applypatch.sample b/spec/.repo/.git-orig/hooks/pre-applypatch.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/pre-applypatch.sample rename to spec/.repo/.git-orig/hooks/pre-applypatch.sample diff --git a/tests/repo_origin/.git-orig/hooks/pre-commit.sample b/spec/.repo/.git-orig/hooks/pre-commit.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/pre-commit.sample rename to spec/.repo/.git-orig/hooks/pre-commit.sample diff --git a/tests/repo_origin/.git-orig/hooks/pre-merge-commit.sample b/spec/.repo/.git-orig/hooks/pre-merge-commit.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/pre-merge-commit.sample rename to spec/.repo/.git-orig/hooks/pre-merge-commit.sample diff --git a/tests/repo_origin/.git-orig/hooks/pre-push.sample b/spec/.repo/.git-orig/hooks/pre-push.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/pre-push.sample rename to spec/.repo/.git-orig/hooks/pre-push.sample diff --git a/tests/repo_origin/.git-orig/hooks/pre-rebase.sample b/spec/.repo/.git-orig/hooks/pre-rebase.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/pre-rebase.sample rename to spec/.repo/.git-orig/hooks/pre-rebase.sample diff --git a/tests/repo_origin/.git-orig/hooks/pre-receive.sample b/spec/.repo/.git-orig/hooks/pre-receive.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/pre-receive.sample rename to spec/.repo/.git-orig/hooks/pre-receive.sample diff --git a/tests/repo_origin/.git-orig/hooks/prepare-commit-msg.sample b/spec/.repo/.git-orig/hooks/prepare-commit-msg.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/prepare-commit-msg.sample rename to spec/.repo/.git-orig/hooks/prepare-commit-msg.sample diff --git a/tests/repo_origin/.git-orig/hooks/update.sample b/spec/.repo/.git-orig/hooks/update.sample similarity index 100% rename from tests/repo_origin/.git-orig/hooks/update.sample rename to spec/.repo/.git-orig/hooks/update.sample diff --git a/tests/repo_origin/.git-orig/index b/spec/.repo/.git-orig/index similarity index 100% rename from tests/repo_origin/.git-orig/index rename to spec/.repo/.git-orig/index diff --git a/tests/repo_origin/.git-orig/info/exclude b/spec/.repo/.git-orig/info/exclude similarity index 100% rename from tests/repo_origin/.git-orig/info/exclude rename to spec/.repo/.git-orig/info/exclude diff --git a/tests/repo_origin/.git-orig/logs/HEAD b/spec/.repo/.git-orig/logs/HEAD similarity index 100% rename from tests/repo_origin/.git-orig/logs/HEAD rename to spec/.repo/.git-orig/logs/HEAD diff --git a/tests/repo_origin/.git-orig/logs/refs/heads/featB b/spec/.repo/.git-orig/logs/refs/heads/featB similarity index 100% rename from tests/repo_origin/.git-orig/logs/refs/heads/featB rename to spec/.repo/.git-orig/logs/refs/heads/featB diff --git a/tests/repo_origin/.git-orig/logs/refs/heads/featC b/spec/.repo/.git-orig/logs/refs/heads/featC similarity index 100% rename from tests/repo_origin/.git-orig/logs/refs/heads/featC rename to spec/.repo/.git-orig/logs/refs/heads/featC diff --git a/tests/repo_origin/.git-orig/logs/refs/heads/master b/spec/.repo/.git-orig/logs/refs/heads/master similarity index 100% rename from tests/repo_origin/.git-orig/logs/refs/heads/master rename to spec/.repo/.git-orig/logs/refs/heads/master diff --git a/tests/repo_origin/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 b/spec/.repo/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 similarity index 100% rename from tests/repo_origin/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 rename to spec/.repo/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 diff --git a/tests/repo_origin/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 b/spec/.repo/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 similarity index 100% rename from tests/repo_origin/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 rename to spec/.repo/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 diff --git a/tests/repo_origin/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 b/spec/.repo/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 similarity index 100% rename from tests/repo_origin/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 rename to spec/.repo/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 diff --git a/tests/repo_origin/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 b/spec/.repo/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 similarity index 100% rename from tests/repo_origin/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 rename to spec/.repo/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 diff --git a/tests/repo_origin/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 b/spec/.repo/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 similarity index 100% rename from tests/repo_origin/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 rename to spec/.repo/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 diff --git a/tests/repo_origin/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 b/spec/.repo/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 similarity index 100% rename from tests/repo_origin/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 rename to spec/.repo/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 diff --git a/tests/repo_origin/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 b/spec/.repo/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 similarity index 100% rename from tests/repo_origin/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 rename to spec/.repo/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 diff --git a/tests/repo_origin/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e b/spec/.repo/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e similarity index 100% rename from tests/repo_origin/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e rename to spec/.repo/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e diff --git a/tests/repo_origin/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 b/spec/.repo/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 similarity index 100% rename from tests/repo_origin/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 rename to spec/.repo/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 diff --git a/tests/repo_origin/.git-orig/refs/heads/featB b/spec/.repo/.git-orig/refs/heads/featB similarity index 100% rename from tests/repo_origin/.git-orig/refs/heads/featB rename to spec/.repo/.git-orig/refs/heads/featB diff --git a/tests/repo_origin/.git-orig/refs/heads/featC b/spec/.repo/.git-orig/refs/heads/featC similarity index 100% rename from tests/repo_origin/.git-orig/refs/heads/featC rename to spec/.repo/.git-orig/refs/heads/featC diff --git a/tests/repo_origin/.git-orig/refs/heads/master b/spec/.repo/.git-orig/refs/heads/master similarity index 100% rename from tests/repo_origin/.git-orig/refs/heads/master rename to spec/.repo/.git-orig/refs/heads/master diff --git a/tests/repo_origin/A.txt b/spec/.repo/A.txt similarity index 100% rename from tests/repo_origin/A.txt rename to spec/.repo/A.txt From 3d49f01bbe31e5c5d6a9ab750825270d8cf0e6cf Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 8 Nov 2023 11:42:07 -0500 Subject: [PATCH 03/33] feat: add ability to run luarocks non nix --- .gitignore | 4 ++++ flake.nix | 1 + git-worktree.nvim-scm-1.rockspec | 3 +++ nix/neorocks-test.nix | 5 ++++- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 03936e0..a498ef9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .zshrc.bak .direnv .pre-commit-config.yaml +/luarocks +/lua +/lua_modules +/.luarocks diff --git a/flake.nix b/flake.nix index 4287ccc..6e23570 100644 --- a/flake.nix +++ b/flake.nix @@ -66,6 +66,7 @@ buildInputs = (with pkgs; [ neorocks + haskellPackages.neolua-bin ]) ++ (with inputs.pre-commit-hooks.packages.${system}; [ alejandra diff --git a/git-worktree.nvim-scm-1.rockspec b/git-worktree.nvim-scm-1.rockspec index cbfef97..4af2105 100644 --- a/git-worktree.nvim-scm-1.rockspec +++ b/git-worktree.nvim-scm-1.rockspec @@ -8,10 +8,12 @@ version = _MODREV .. _SPECREV dependencies = { 'lua >= 5.1', + 'plenary.nvim' } test_dependencies = { 'lua >= 5.1', + 'plenary.nvim' } source = { @@ -22,5 +24,6 @@ build = { type = 'builtin', copy_directories = { 'doc', + 'tests' }, } diff --git a/nix/neorocks-test.nix b/nix/neorocks-test.nix index b281b8b..5953096 100644 --- a/nix/neorocks-test.nix +++ b/nix/neorocks-test.nix @@ -1,5 +1,6 @@ { extraPkgs ? [], + git, name, neorocksTest, nvim, @@ -24,7 +25,9 @@ in neovim = nvim-wrapped; extraPackages = - [] + [ + git + ] ++ extraPkgs; preCheck = '' From a1f8d434fdf70d0602168adb18e7bfecb6e408c0 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 8 Nov 2023 12:52:39 -0500 Subject: [PATCH 04/33] test: add git ops tests --- .busted | 2 +- .gitignore | 1 - flake.nix | 7 ++- git-worktree.nvim-scm-1.rockspec | 1 - lua/git-worktree/git.lua | 86 +++++++++++++++++--------------- spec/git_spec.lua | 40 +++++++++++++++ spec/util/git_harness.lua | 64 ++++++++++++++++++++++++ spec/util/system.lua | 41 +++++++++++++++ 8 files changed, 198 insertions(+), 44 deletions(-) create mode 100644 spec/git_spec.lua create mode 100644 spec/util/git_harness.lua create mode 100644 spec/util/system.lua diff --git a/.busted b/.busted index 6c370f4..5d91aed 100644 --- a/.busted +++ b/.busted @@ -1,7 +1,7 @@ return { _all = { coverage = false, - lpath = "lua/?.lua;lua/?/init.lua", + lpath = "lua/?.lua;lua/?/init.lua;spec/?.lua;spec/?/init.lua", }, default = { verbose = true diff --git a/.gitignore b/.gitignore index a498ef9..26dc7e5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,5 @@ .direnv .pre-commit-config.yaml /luarocks -/lua /lua_modules /.luarocks diff --git a/flake.nix b/flake.nix index 6e23570..1eca475 100644 --- a/flake.nix +++ b/flake.nix @@ -62,7 +62,11 @@ devShells = { default = pkgs.mkShell { name = "haskell-tools.nvim-shell"; - inherit (pre-commit-check) shellHook; + shellHook = + pre-commit-check.shellHook + + '' + export RT_LIBDIR=${pkgs.glibc} + ''; buildInputs = (with pkgs; [ neorocks @@ -75,6 +79,7 @@ #luacheck #markdownlint-cli ]); + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath []; }; }; diff --git a/git-worktree.nvim-scm-1.rockspec b/git-worktree.nvim-scm-1.rockspec index 4af2105..ccfb0db 100644 --- a/git-worktree.nvim-scm-1.rockspec +++ b/git-worktree.nvim-scm-1.rockspec @@ -24,6 +24,5 @@ build = { type = 'builtin', copy_directories = { 'doc', - 'tests' }, } diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index e9e342f..6f64d1b 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -1,4 +1,4 @@ -local Job = require("plenary.job") +local Job = require("plenary").job local Path = require("plenary.path") local Status = require("git-worktree.status") @@ -57,53 +57,59 @@ end --- @param is_worktree boolean --- @return string|nil -function M.find_git_dir(is_worktree) - local find_git_dir_job = Job:new({ +function M.find_git_dir() + local job = Job:new { 'git', 'rev-parse', - '--absolute-git-dir', + '--show-toplevel', cwd = vim.loop.cwd(), - }) + on_stderr = function(_, data) + status:log().info("ERROR: " .. data) + end, + } - local stdout, code = find_git_dir_job:sync() + local stdout, code = job:sync() if code ~= 0 then - status:log().error("Error in determining the git root dir") + status:log().error("Error in determining the git root dir: code:" .. + tostring(code) .. " out: " .. table.concat(stdout, "") .. ".") return nil end stdout = table.concat(stdout, "") - - if is_worktree then - -- if in worktree git dir returns absolute path - - -- try to find the dot git folder (non-bare repo) - local git_dir = Path:new(stdout) - local has_dot_git = false - for _, dir in ipairs(git_dir:_split()) do - if dir == ".git" then - has_dot_git = true - break - end - end - - if has_dot_git then - if stdout == ".git" then - return vim.loop.cwd() - else - local start = stdout:find("%.git") - return stdout:sub(1, start - 2) - end - else - local start = stdout:find("/worktrees/") - return stdout:sub(0, start - 1) - end - elseif stdout == "." then - -- we are in the root git dir - return vim.loop.cwd() - else - -- if not in worktree git dir should be absolute - return stdout - end + status:log().info("cwd: " .. vim.loop.cwd()) + status:log().info("git root dir: " .. stdout) + + -- if is_worktree then + -- -- if in worktree git dir returns absolute path + -- + -- -- try to find the dot git folder (non-bare repo) + -- local git_dir = Path:new(stdout) + -- local has_dot_git = false + -- for _, dir in ipairs(git_dir:_split()) do + -- if dir == ".git" then + -- has_dot_git = true + -- break + -- end + -- end + -- + -- if has_dot_git then + -- if stdout == ".git" then + -- return vim.loop.cwd() + -- else + -- local start = stdout:find("%.git") + -- return stdout:sub(1, start - 2) + -- end + -- else + -- local start = stdout:find("/worktrees/") + -- return stdout:sub(0, start - 1) + -- end + -- elseif stdout == "." then + -- -- we are in the root git dir + -- return vim.loop.cwd() + -- else + -- if not in worktree git dir should be absolute + return stdout + -- end end --- @return string|nil @@ -112,7 +118,7 @@ function M.find_git_toplevel() 'git', 'rev-parse', '--show-toplevel', - cwd = cwd, + cwd = vim.loop.cwd(), }) local stdout, code = find_toplevel_job:sync() if code == 0 then diff --git a/spec/git_spec.lua b/spec/git_spec.lua new file mode 100644 index 0000000..c0a6e96 --- /dev/null +++ b/spec/git_spec.lua @@ -0,0 +1,40 @@ +local git_harness = require('util.git_harness') +local gwt_git = require('git-worktree.git') +local Status = require("git-worktree.status") + +local status = Status:new() + + +describe('git-worktree git operations', function() + describe('finds git toplevel in normal repo', function() + before_each(function() + repo_dir = git_harness.prepare_repo() + end) + it('Public API is available after setup.', function() + local ret_git_dir = gwt_git.find_git_dir() + assert.are.same(ret_git_dir, repo_dir) + end) + end) + + describe('finds git toplevel in bare repo', function() + before_each(function() + repo_dir = git_harness.prepare_repo_bare() + end) + it('no toplevel in a bare repo', function() + local ret_git_dir = gwt_git.find_git_dir() + assert.are.same(ret_git_dir, nil) + end) + end) + + describe('finds git toplevel in worktree repo', function() + before_each(function() + repo_dir = git_harness.prepare_repo_worktree() + end) + it('Public API is available after setup.', function() + local ret_git_dir = gwt_git.find_git_dir() + status:log().info("ret_git_dir: " .. ret_git_dir .. ".") + status:log().info("repo_dir : " .. repo_dir .. ".") + assert.are.same(ret_git_dir, repo_dir) + end) + end) +end) diff --git a/spec/util/git_harness.lua b/spec/util/git_harness.lua new file mode 100644 index 0000000..299acb5 --- /dev/null +++ b/spec/util/git_harness.lua @@ -0,0 +1,64 @@ +local system = require('util.system') + +local M = {} + +local origin_repo_path = nil + +function M.setup_origin_repo() + if origin_repo_path ~= nil then + return origin_repo_path + end + + local workspace_dir = system.create_temp_dir("workspace-dir") + vim.api.nvim_set_current_dir(vim.fn.getcwd()) + system.run("cp -r spec/.repo " .. workspace_dir) + vim.api.nvim_set_current_dir(workspace_dir) + system.run([[ + mv .repo/.git-orig ./.git + mv .repo/* . + git config user.email "test@test.test" + git config user.name "Test User" + ]]) + + origin_repo_path = system.create_temp_dir("origin-repo") + system.run(string.format("git clone --bare %s %s", workspace_dir, origin_repo_path)) + + return origin_repo_path +end + +function M.prepare_repo() + M.setup_origin_repo() + + local working_dir = system.create_temp_dir("working-dir") + vim.api.nvim_set_current_dir(working_dir) + system.run(string.format("git clone %s %s", origin_repo_path, working_dir)) + system.run([[ + git config remote.origin.url git@github.com:test/test.git + git config user.email "test@test.test" + git config user.name "Test User" + ]]) + return working_dir +end + +function M.prepare_repo_bare() + M.setup_origin_repo() + + local working_dir = system.create_temp_dir("working-bare-dir") + vim.api.nvim_set_current_dir(working_dir) + system.run(string.format("git clone --bare %s %s", origin_repo_path, working_dir)) + return working_dir +end + +function M.prepare_repo_worktree() + M.setup_origin_repo() + + local working_dir = system.create_temp_dir("working-worktree-dir") + vim.api.nvim_set_current_dir(working_dir) + system.run(string.format("git clone --bare %s %s", origin_repo_path, working_dir)) + system.run("git worktree add wt master") + local worktree_dir = working_dir .. "/wt" + vim.api.nvim_set_current_dir(worktree_dir) + return worktree_dir +end + +return M diff --git a/spec/util/system.lua b/spec/util/system.lua new file mode 100644 index 0000000..67f0408 --- /dev/null +++ b/spec/util/system.lua @@ -0,0 +1,41 @@ +local M = {} + +---Runs a system command and errors if it fails +---@param cmd string | table Command to be ran +---@param ignore_err boolean? Whether the error should be ignored +---@param error_msg string? The error message to be emitted on command failure +---@return string The output of the system command +function M.run(cmd, ignore_err, error_msg) + if ignore_err == nil then + ignore_err = false + end + + local output = vim.fn.system(cmd) + if vim.v.shell_error ~= 0 and not ignore_err then + error(error_msg or ("Command failed: ↓\n" .. cmd .. "\nOutput from command: ↓\n" .. output)) + end + return output +end + +local function is_macos() + return vim.loop.os_uname().sysname == "Darwin" +end + +---Create a temporary directory for use +---@param suffix string? The suffix to be appended to the temp directory, ideally avoid spaces in your suffix +---@return string The path to the temporary directory +function M.create_temp_dir(suffix) + suffix = "git-worktree-" .. (suffix or "") + + local cmd + if is_macos() then + cmd = string.format("mktemp -d -t %s", suffix) + else + cmd = string.format("mktemp -d --suffix=%s", suffix) + end + + local prefix = is_macos() and "/private" or "" + return prefix .. vim.trim(M.run(cmd)) +end + +return M From 2415a4d17d4ef9b048cbb3e05d888d92f0582b41 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 8 Nov 2023 20:27:22 -0500 Subject: [PATCH 05/33] chore: fix stylua --- flake.nix | 16 +- lua/git-worktree/config.lua | 3 + lua/git-worktree/enum.lua | 5 +- lua/git-worktree/git.lua | 49 +- lua/git-worktree/hooks.lua | 5 +- lua/git-worktree/init.lua | 67 +- lua/git-worktree/status.lua | 5 +- lua/git-worktree/test.lua | 4 - lua/telescope/_extensions/git_worktree.lua | 113 +- nix/neorocks-test.nix | 7 + nix/type-check.nix | 2 +- spec/git_spec.lua | 19 +- spec/setup_spec.lua | 4 +- spec/util/git_harness.lua | 2 +- tests/git_harness.lua | 124 +- tests/worktree_spec.lua | 1344 +++++++++----------- 16 files changed, 811 insertions(+), 958 deletions(-) create mode 100644 lua/git-worktree/config.lua diff --git a/flake.nix b/flake.nix index 1eca475..4fee52d 100644 --- a/flake.nix +++ b/flake.nix @@ -47,7 +47,7 @@ src = self; hooks = { alejandra.enable = true; - #stylua.enable = true; + stylua.enable = true; #luacheck.enable = true; #markdownlint.enable = true; }; @@ -62,11 +62,7 @@ devShells = { default = pkgs.mkShell { name = "haskell-tools.nvim-shell"; - shellHook = - pre-commit-check.shellHook - + '' - export RT_LIBDIR=${pkgs.glibc} - ''; + inherit (pre-commit-check) shellHook; buildInputs = (with pkgs; [ neorocks @@ -74,10 +70,10 @@ ]) ++ (with inputs.pre-commit-hooks.packages.${system}; [ alejandra - #lua-language-server - #stylua - #luacheck - #markdownlint-cli + lua-language-server + stylua + luacheck + markdownlint-cli ]); LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath []; }; diff --git a/lua/git-worktree/config.lua b/lua/git-worktree/config.lua new file mode 100644 index 0000000..5044d6f --- /dev/null +++ b/lua/git-worktree/config.lua @@ -0,0 +1,3 @@ +local M = {} + +return M diff --git a/lua/git-worktree/enum.lua b/lua/git-worktree/enum.lua index a98b6f7..d58150a 100644 --- a/lua/git-worktree/enum.lua +++ b/lua/git-worktree/enum.lua @@ -15,8 +15,5 @@ return { Create = "create", Switch = "switch", Delete = "delete", - }) + }), } - - - diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index 6f64d1b..d0d323c 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -10,9 +10,9 @@ local M = {} --- @return boolean function M.is_bare_repo() local inside_worktree_job = Job:new({ - 'git', - 'rev-parse', - '--is-bare-repository', + "git", + "rev-parse", + "--is-bare-repository", cwd = vim.loop.cwd(), }) @@ -34,9 +34,9 @@ end --- @return boolean function M.is_worktree() local inside_worktree_job = Job:new({ - 'git', - 'rev-parse', - '--is-inside-work-tree', + "git", + "rev-parse", + "--is-inside-work-tree", cwd = vim.loop.cwd(), }) @@ -58,20 +58,25 @@ end --- @param is_worktree boolean --- @return string|nil function M.find_git_dir() - local job = Job:new { - 'git', - 'rev-parse', - '--show-toplevel', + local job = Job:new({ + "git", + "rev-parse", + "--show-toplevel", cwd = vim.loop.cwd(), on_stderr = function(_, data) status:log().info("ERROR: " .. data) end, - } + }) local stdout, code = job:sync() if code ~= 0 then - status:log().error("Error in determining the git root dir: code:" .. - tostring(code) .. " out: " .. table.concat(stdout, "") .. ".") + status:log().error( + "Error in determining the git root dir: code:" + .. tostring(code) + .. " out: " + .. table.concat(stdout, "") + .. "." + ) return nil end @@ -115,9 +120,9 @@ end --- @return string|nil function M.find_git_toplevel() local find_toplevel_job = Job:new({ - 'git', - 'rev-parse', - '--show-toplevel', + "git", + "rev-parse", + "--show-toplevel", cwd = vim.loop.cwd(), }) local stdout, code = find_toplevel_job:sync() @@ -132,8 +137,8 @@ end function M.has_branch(branch, cb) local found = false local job = Job:new({ - 'git', - 'branch', + "git", + "branch", on_stdout = function(_, data) -- remove markere on current branch data = data:gsub("*", "") @@ -154,12 +159,12 @@ end function M.has_origin() local found = false local job = Job:new({ - 'git', - 'remote', - 'show', + "git", + "remote", + "show", on_stdout = function(_, data) data = vim.trim(data) - found = found or data == 'origin' + found = found or data == "origin" end, cwd = vim.loop.cwd(), }) diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 70980bb..6f9718e 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -6,8 +6,9 @@ local function on_tree_change_handler(op, metadata) if op == Enum.Operations.Switch then local changed = M.update_current_buffer(metadata["prev_path"]) if not changed then - status:log().debug( - "Could not change to the file in the new worktree, running the `update_on_change_command`") + status + :log() + .debug("Could not change to the file in the new worktree, running the `update_on_change_command`") vim.cmd(M._config.update_on_change_command) end end diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index 79d387c..0dc0120 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -10,7 +10,6 @@ local git_worktree_root = nil local current_worktree_path = nil local on_change_callbacks = {} - local function change_dirs(path) local worktree_path = M.get_worktree_path(path) @@ -23,7 +22,7 @@ local function change_dirs(path) vim.cmd(cmd) current_worktree_path = worktree_path else - status:error('Could not chang to directory: ' .. worktree_path) + status:error("Could not chang to directory: " .. worktree_path) end if M._config.clearjumps_on_change then @@ -35,11 +34,11 @@ local function change_dirs(path) end local function create_worktree_job(path, branch, found_branch) - local worktree_add_cmd = 'git' - local worktree_add_args = { 'worktree', 'add' } + local worktree_add_cmd = "git" + local worktree_add_args = { "worktree", "add" } if not found_branch then - table.insert(worktree_add_args, '-b') + table.insert(worktree_add_args, "-b") table.insert(worktree_add_args, branch) table.insert(worktree_add_args, path) else @@ -53,7 +52,7 @@ local function create_worktree_job(path, branch, found_branch) cwd = git_worktree_root, on_start = function() status:next_status(worktree_add_cmd .. " " .. table.concat(worktree_add_args, " ")) - end + end, }) end @@ -64,9 +63,9 @@ local function has_worktree(path, cb) local plenary_path = Path:new(path) local job = Job:new({ - 'git', - 'worktree', - 'list', + "git", + "worktree", + "list", on_stdout = function(_, data) local list_data = {} for section in data:gmatch("%S+") do @@ -79,9 +78,7 @@ local function has_worktree(path, cb) if plenary_path:is_absolute() then start = data == path else - local worktree_path = Path:new( - string.format("%s" .. Path.path.sep .. "%s", git_worktree_root, path) - ) + local worktree_path = Path:new(string.format("%s" .. Path.path.sep .. "%s", git_worktree_root, path)) worktree_path = worktree_path:absolute() start = data == worktree_path end @@ -90,7 +87,7 @@ local function has_worktree(path, cb) local start_with_head = string.find(data, string.format("[heads/%s]", path), 1, true) found = found or start or start_with_head end, - cwd = git_worktree_root + cwd = git_worktree_root, }) job:after(function() @@ -110,7 +107,8 @@ local function failure(from, cmd, path, soft_error) path, vim.inspect(cmd), vim.inspect(e:result()), - vim.inspect(e:stderr_result())) + vim.inspect(e:stderr_result()) + ) if soft_error then status:status(error_message) @@ -120,8 +118,6 @@ local function failure(from, cmd, path, soft_error) end end - - local function create_worktree(path, branch, upstream, found_branch) local create = create_worktree_job(path, branch, found_branch) @@ -132,47 +128,47 @@ local function create_worktree(path, branch, upstream, found_branch) worktree_path = Path:new(git_worktree_root, path):absolute() end - local fetch = Job:new({ - 'git', - 'fetch', - '--all', + local fetch = Job:new({ + "git", + "fetch", + "--all", cwd = worktree_path, on_start = function() status:next_status("git fetch --all (This may take a moment)") - end + end, }) - local set_branch_cmd = 'git' - local set_branch_args = { 'branch', string.format('--set-upstream-to=%s/%s', upstream, branch) } - local set_branch = Job:new({ + local set_branch_cmd = "git" + local set_branch_args = { "branch", string.format("--set-upstream-to=%s/%s", upstream, branch) } + local set_branch = Job:new({ command = set_branch_cmd, args = set_branch_args, cwd = worktree_path, on_start = function() status:next_status(set_branch_cmd .. " " .. table.concat(set_branch_args, " ")) - end + end, }) -- TODO: How to configure origin??? Should upstream ever be the push -- destination? - local set_push_cmd = 'git' - local set_push_args = { 'push', "--set-upstream", upstream, branch, path } - local set_push = Job:new({ + local set_push_cmd = "git" + local set_push_args = { "push", "--set-upstream", upstream, branch, path } + local set_push = Job:new({ command = set_push_cmd, args = set_push_args, cwd = worktree_path, on_start = function() status:next_status(set_push_cmd .. " " .. table.concat(set_push_args, " ")) - end + end, }) - local rebase = Job:new({ - 'git', - 'rebase', + local rebase = Job:new({ + "git", + "rebase", cwd = worktree_path, on_start = function() status:next_status("git rebase") - end + end, }) if upstream ~= nil then @@ -266,7 +262,10 @@ M.delete_worktree = function(path, force, opts) end local cmd = { - "git", "worktree", "remove", path + "git", + "worktree", + "remove", + path, } if force then diff --git a/lua/git-worktree/status.lua b/lua/git-worktree/status.lua index e1e5825..f479659 100644 --- a/lua/git-worktree/status.lua +++ b/lua/git-worktree/status.lua @@ -13,14 +13,13 @@ local function set_log_level() return "warn" -- default, if user hasn't set to one from log_levels end - function Status:new(options) - local obj = vim.tbl_extend('force', { + local obj = vim.tbl_extend("force", { -- What to do here? logger = require("plenary.log").new({ plugin = "git-worktree-nvim", level = set_log_level(), - }) + }), }, options or {}) setmetatable(obj, self) diff --git a/lua/git-worktree/test.lua b/lua/git-worktree/test.lua index 3906c9a..3db2700 100644 --- a/lua/git-worktree/test.lua +++ b/lua/git-worktree/test.lua @@ -1,8 +1,4 @@ - local Path = require("plenary.path") local path = Path:new(vim.loop.cwd(), "foo", "..", "..") - print(path:absolute()) - - diff --git a/lua/telescope/_extensions/git_worktree.lua b/lua/telescope/_extensions/git_worktree.lua index 96c2b33..33c7720 100644 --- a/lua/telescope/_extensions/git_worktree.lua +++ b/lua/telescope/_extensions/git_worktree.lua @@ -28,11 +28,11 @@ end local toggle_forced_deletion = function() -- redraw otherwise the message is not displayed when in insert mode if force_next_deletion then - print('The next deletion will not be forced') - vim.fn.execute('redraw') + print("The next deletion will not be forced") + vim.fn.execute("redraw") else - print('The next deletion will be forced') - vim.fn.execute('redraw') + print("The next deletion will be forced") + vim.fn.execute("redraw") force_next_deletion = true end end @@ -78,7 +78,7 @@ local delete_worktree = function(prompt_bufnr) if worktree_path ~= nil then git_worktree.delete_worktree(worktree_path, force_next_deletion, { on_failure = delete_failure_handler, - on_success = delete_success_handler + on_success = delete_success_handler, }) end end @@ -111,27 +111,25 @@ end local create_worktree = function(opts) opts = opts or {} opts.attach_mappings = function() - actions.select_default:replace( - function(prompt_bufnr, _) - local selected_entry = action_state.get_selected_entry() - local current_line = action_state.get_current_line() + actions.select_default:replace(function(prompt_bufnr, _) + local selected_entry = action_state.get_selected_entry() + local current_line = action_state.get_current_line() - actions.close(prompt_bufnr) + actions.close(prompt_bufnr) - local branch = selected_entry ~= nil and - selected_entry.value or current_line + local branch = selected_entry ~= nil and selected_entry.value or current_line - if branch == nil then - return - end + if branch == nil then + return + end - create_input_prompt(function(name) - if name == "" then - name = branch - end - git_worktree.create_worktree(name, branch) - end) + create_input_prompt(function(name) + if name == "" then + name = branch + end + git_worktree.create_worktree(name, branch) end) + end) -- do we need to replace other default maps? @@ -147,7 +145,7 @@ local telescope_git_worktree = function(opts) local widths = { path = 0, sha = 0, - branch = 0 + branch = 0, } local parse_line = function(line) @@ -161,7 +159,7 @@ local telescope_git_worktree = function(opts) if entry.sha ~= "(bare)" then local index = #results + 1 for key, val in pairs(widths) do - if key == 'path' then + if key == "path" then local new_path = utils.transform_path(opts, entry[key]) local path_len = strings.strdisplaywidth(new_path or "") widths[key] = math.max(val, path_len) @@ -182,52 +180,53 @@ local telescope_git_worktree = function(opts) return end - local displayer = require("telescope.pickers.entry_display").create { + local displayer = require("telescope.pickers.entry_display").create({ separator = " ", items = { { width = widths.branch }, { width = widths.path }, { width = widths.sha }, }, - } + }) local make_display = function(entry) - return displayer { - { entry.branch, "TelescopeResultsIdentifier" }, + return displayer({ + { entry.branch, "TelescopeResultsIdentifier" }, { utils.transform_path(opts, entry.path) }, { entry.sha }, - } + }) end - pickers.new(opts or {}, { - prompt_title = "Git Worktrees", - finder = finders.new_table { - results = results, - entry_maker = function(entry) - entry.value = entry.branch - entry.ordinal = entry.branch - entry.display = make_display - return entry + pickers + .new(opts or {}, { + prompt_title = "Git Worktrees", + finder = finders.new_table({ + results = results, + entry_maker = function(entry) + entry.value = entry.branch + entry.ordinal = entry.branch + entry.display = make_display + return entry + end, + }), + sorter = conf.generic_sorter(opts), + attach_mappings = function(_, map) + action_set.select:replace(switch_worktree) + + map("i", "", delete_worktree) + map("n", "", delete_worktree) + map("i", "", toggle_forced_deletion) + map("n", "", toggle_forced_deletion) + + return true end, - }, - sorter = conf.generic_sorter(opts), - attach_mappings = function(_, map) - action_set.select:replace(switch_worktree) - - map("i", "", delete_worktree) - map("n", "", delete_worktree) - map("i", "", toggle_forced_deletion) - map("n", "", toggle_forced_deletion) - - return true - end - }):find() + }) + :find() end -return require("telescope").register_extension( - { - exports = { - git_worktree = telescope_git_worktree, - create_git_worktree = create_worktree - } - }) +return require("telescope").register_extension({ + exports = { + git_worktree = telescope_git_worktree, + create_git_worktree = create_worktree, + }, +}) diff --git a/nix/neorocks-test.nix b/nix/neorocks-test.nix index 5953096..6425eaa 100644 --- a/nix/neorocks-test.nix +++ b/nix/neorocks-test.nix @@ -1,4 +1,5 @@ { + curl, extraPkgs ? [], git, name, @@ -27,8 +28,14 @@ in extraPackages = [ git + curl ] ++ extraPkgs; + luaPackages = ps: + with ps; [ + # LuaRocks dependencies must be added here. + plenary-nvim + ]; preCheck = '' # Neovim expects to be able to create log files, etc. diff --git a/nix/type-check.nix b/nix/type-check.nix index b67d288..85f01e4 100644 --- a/nix/type-check.nix +++ b/nix/type-check.nix @@ -36,7 +36,7 @@ "result" "nix" "doc" - "spec" # FIXME: Add busted library + "spec" ]; }; diagnostics = { diff --git a/spec/git_spec.lua b/spec/git_spec.lua index c0a6e96..1b23045 100644 --- a/spec/git_spec.lua +++ b/spec/git_spec.lua @@ -1,36 +1,35 @@ -local git_harness = require('util.git_harness') -local gwt_git = require('git-worktree.git') +local git_harness = require("util.git_harness") +local gwt_git = require("git-worktree.git") local Status = require("git-worktree.status") local status = Status:new() - -describe('git-worktree git operations', function() - describe('finds git toplevel in normal repo', function() +describe("git-worktree git operations", function() + describe("finds git toplevel in normal repo", function() before_each(function() repo_dir = git_harness.prepare_repo() end) - it('Public API is available after setup.', function() + it("Public API is available after setup.", function() local ret_git_dir = gwt_git.find_git_dir() assert.are.same(ret_git_dir, repo_dir) end) end) - describe('finds git toplevel in bare repo', function() + describe("finds git toplevel in bare repo", function() before_each(function() repo_dir = git_harness.prepare_repo_bare() end) - it('no toplevel in a bare repo', function() + it("no toplevel in a bare repo", function() local ret_git_dir = gwt_git.find_git_dir() assert.are.same(ret_git_dir, nil) end) end) - describe('finds git toplevel in worktree repo', function() + describe("finds git toplevel in worktree repo", function() before_each(function() repo_dir = git_harness.prepare_repo_worktree() end) - it('Public API is available after setup.', function() + it("Public API is available after setup.", function() local ret_git_dir = gwt_git.find_git_dir() status:log().info("ret_git_dir: " .. ret_git_dir .. ".") status:log().info("repo_dir : " .. repo_dir .. ".") diff --git a/spec/setup_spec.lua b/spec/setup_spec.lua index 34d7867..d6b6ba4 100644 --- a/spec/setup_spec.lua +++ b/spec/setup_spec.lua @@ -1,5 +1,5 @@ -describe('Can require haskell-tools with default configs.', function() - it('Public API is available after setup.', function() +describe("Can require haskell-tools with default configs.", function() + it("Public API is available after setup.", function() assert(1 == 1) end) end) diff --git a/spec/util/git_harness.lua b/spec/util/git_harness.lua index 299acb5..0d577fa 100644 --- a/spec/util/git_harness.lua +++ b/spec/util/git_harness.lua @@ -1,4 +1,4 @@ -local system = require('util.system') +local system = require("util.system") local M = {} diff --git a/tests/git_harness.lua b/tests/git_harness.lua index afa216b..2c2682c 100644 --- a/tests/git_harness.lua +++ b/tests/git_harness.lua @@ -1,5 +1,5 @@ -local git_worktree = require('git-worktree') -local Job = require('plenary.job') +local git_worktree = require("git-worktree") +local Job = require("plenary.job") local Path = require("plenary.path") local M = {} @@ -13,18 +13,18 @@ local get_os_command_output = function(cmd) cwd = git_worktree.get_root(), on_stderr = function(_, data) table.insert(stderr, data) - end + end, }):sync() return stdout, ret, stderr end local prepare_origin_repo = function(dir) - vim.api.nvim_exec('!cp -r tests/repo_origin/ /tmp/' .. dir, true) - vim.api.nvim_exec('!mv /tmp/'..dir..'/.git-orig /tmp/'..dir..'/.git', true) + vim.api.nvim_exec("!cp -r tests/repo_origin/ /tmp/" .. dir, true) + vim.api.nvim_exec("!mv /tmp/" .. dir .. "/.git-orig /tmp/" .. dir .. "/.git", true) end local prepare_bare_repo = function(dir, origin_dir) - vim.api.nvim_exec('!git clone --bare /tmp/'..origin_dir..' /tmp/'..dir, true) + vim.api.nvim_exec("!git clone --bare /tmp/" .. origin_dir .. " /tmp/" .. dir, true) end local fix_fetch_all = function() @@ -32,36 +32,36 @@ local fix_fetch_all = function() end local prepare_repo = function(dir, origin_dir) - vim.api.nvim_exec('!git clone /tmp/'..origin_dir..' /tmp/'..dir, true) + vim.api.nvim_exec("!git clone /tmp/" .. origin_dir .. " /tmp/" .. dir, true) end local random_string = function() - math.randomseed(os.clock()^5) + math.randomseed(os.clock() ^ 5) local ret = "" for _ = 1, 5 do - local random_char = math.random(97,122) + local random_char = math.random(97, 122) ret = ret .. string.char(random_char) end return ret end local change_dir = function(dir) - vim.api.nvim_set_current_dir('/tmp/'..dir) - git_worktree.set_worktree_root('/tmp/'..dir) + vim.api.nvim_set_current_dir("/tmp/" .. dir) + git_worktree.set_worktree_root("/tmp/" .. dir) end local cleanup_repos = function() - vim.api.nvim_exec('silent !rm -rf /tmp/git_worktree_test*', true) + vim.api.nvim_exec("silent !rm -rf /tmp/git_worktree_test*", true) end local create_worktree = function(folder_path, commitish) - vim.api.nvim_exec('!git worktree add ' .. folder_path .. ' ' .. commitish, true) + vim.api.nvim_exec("!git worktree add " .. folder_path .. " " .. commitish, true) end -local project_dir = vim.api.nvim_exec('pwd', true) +local project_dir = vim.api.nvim_exec("pwd", true) local reset_cwd = function() - vim.cmd('cd ' .. project_dir) + vim.cmd("cd " .. project_dir) vim.api.nvim_set_current_dir(project_dir) end @@ -89,15 +89,14 @@ M.in_non_git_repo = function(cb) if err ~= nil then error(err) end - end end M.in_bare_repo_from_origin_no_worktrees = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local bare_repo_dir = 'git_worktree_test_repo_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local bare_repo_dir = "git_worktree_test_repo_" .. random_id config_git_worktree() cleanup_repos() @@ -117,15 +116,14 @@ M.in_bare_repo_from_origin_no_worktrees = function(cb) if err ~= nil then error(err) end - end end M.in_repo_from_origin_no_worktrees = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local repo_dir = 'git_worktree_test_repo_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local repo_dir = "git_worktree_test_repo_" .. random_id config_git_worktree() cleanup_repos() @@ -144,14 +142,13 @@ M.in_repo_from_origin_no_worktrees = function(cb) if err ~= nil then error(err) end - end end M.in_repo_from_local_no_worktrees = function(cb) return function() local random_id = random_string() - local local_repo_dir = 'git_worktree_test_origin_repo_' .. random_id + local local_repo_dir = "git_worktree_test_origin_repo_" .. random_id config_git_worktree() cleanup_repos() @@ -169,15 +166,14 @@ M.in_repo_from_local_no_worktrees = function(cb) if err ~= nil then error(err) end - end end M.in_bare_repo_from_origin_1_worktree = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local bare_repo_dir = 'git_worktree_test_repo_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local bare_repo_dir = "git_worktree_test_repo_" .. random_id config_git_worktree() cleanup_repos() @@ -185,7 +181,7 @@ M.in_bare_repo_from_origin_1_worktree = function(cb) prepare_origin_repo(origin_repo_dir) prepare_bare_repo(bare_repo_dir, origin_repo_dir) change_dir(bare_repo_dir) - create_worktree('master','master') + create_worktree("master", "master") local _, err = pcall(cb) @@ -196,16 +192,15 @@ M.in_bare_repo_from_origin_1_worktree = function(cb) if err ~= nil then error(err) end - end end M.in_repo_from_origin_1_worktree = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local repo_dir = 'git_worktree_test_repo_' .. random_id - local feat_dir = 'git_worktree_test_repo_featB_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local repo_dir = "git_worktree_test_repo_" .. random_id + local feat_dir = "git_worktree_test_repo_featB_" .. random_id config_git_worktree() cleanup_repos() @@ -214,7 +209,7 @@ M.in_repo_from_origin_1_worktree = function(cb) prepare_repo(repo_dir, origin_repo_dir) change_dir(repo_dir) - create_worktree('../'..feat_dir,'featB') + create_worktree("../" .. feat_dir, "featB") local _, err = pcall(cb) @@ -225,15 +220,14 @@ M.in_repo_from_origin_1_worktree = function(cb) if err ~= nil then error(err) end - end end M.in_bare_repo_from_origin_2_worktrees = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local bare_repo_dir = 'git_worktree_test_repo_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local bare_repo_dir = "git_worktree_test_repo_" .. random_id config_git_worktree() cleanup_repos() @@ -241,8 +235,8 @@ M.in_bare_repo_from_origin_2_worktrees = function(cb) prepare_origin_repo(origin_repo_dir) prepare_bare_repo(bare_repo_dir, origin_repo_dir) change_dir(bare_repo_dir) - create_worktree('featB','featB') - create_worktree('featC','featC') + create_worktree("featB", "featB") + create_worktree("featC", "featC") local _, err = pcall(cb) @@ -253,17 +247,16 @@ M.in_bare_repo_from_origin_2_worktrees = function(cb) if err ~= nil then error(err) end - end end M.in_repo_from_origin_2_worktrees = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local repo_dir = 'git_worktree_test_repo_' .. random_id - local featB_dir = 'git_worktree_test_repo_featB_' .. random_id - local featC_dir = 'git_worktree_test_repo_featC_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local repo_dir = "git_worktree_test_repo_" .. random_id + local featB_dir = "git_worktree_test_repo_featB_" .. random_id + local featC_dir = "git_worktree_test_repo_featC_" .. random_id config_git_worktree() cleanup_repos() @@ -272,8 +265,8 @@ M.in_repo_from_origin_2_worktrees = function(cb) prepare_repo(repo_dir, origin_repo_dir) change_dir(repo_dir) - create_worktree('../'..featB_dir,'featB') - create_worktree('../'..featC_dir,'featC') + create_worktree("../" .. featB_dir, "featB") + create_worktree("../" .. featC_dir, "featC") local _, err = pcall(cb) @@ -284,15 +277,14 @@ M.in_repo_from_origin_2_worktrees = function(cb) if err ~= nil then error(err) end - end end M.in_bare_repo_from_origin_2_similar_named_worktrees = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local bare_repo_dir = 'git_worktree_test_repo_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local bare_repo_dir = "git_worktree_test_repo_" .. random_id config_git_worktree() cleanup_repos() @@ -300,8 +292,8 @@ M.in_bare_repo_from_origin_2_similar_named_worktrees = function(cb) prepare_origin_repo(origin_repo_dir) prepare_bare_repo(bare_repo_dir, origin_repo_dir) change_dir(bare_repo_dir) - create_worktree('featB','featB') - create_worktree('featB-test','featC') + create_worktree("featB", "featB") + create_worktree("featB-test", "featC") local _, err = pcall(cb) @@ -312,17 +304,16 @@ M.in_bare_repo_from_origin_2_similar_named_worktrees = function(cb) if err ~= nil then error(err) end - end end M.in_repo_from_origin_2_similar_named_worktrees = function(cb) return function() local random_id = random_string() - local origin_repo_dir = 'git_worktree_test_origin_repo_' .. random_id - local repo_dir = 'git_worktree_test_repo_' .. random_id - local featB_dir = 'git_worktree_test_repo_featB_' .. random_id - local featC_dir = 'git_worktree_test_repo_featB-test_' .. random_id + local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id + local repo_dir = "git_worktree_test_repo_" .. random_id + local featB_dir = "git_worktree_test_repo_featB_" .. random_id + local featC_dir = "git_worktree_test_repo_featB-test_" .. random_id config_git_worktree() cleanup_repos() @@ -331,8 +322,8 @@ M.in_repo_from_origin_2_similar_named_worktrees = function(cb) prepare_repo(repo_dir, origin_repo_dir) change_dir(repo_dir) - create_worktree('../'..featB_dir,'featB') - create_worktree('../'..featC_dir,'featC') + create_worktree("../" .. featB_dir, "featB") + create_worktree("../" .. featC_dir, "featC") local _, err = pcall(cb) @@ -343,13 +334,16 @@ M.in_repo_from_origin_2_similar_named_worktrees = function(cb) if err ~= nil then error(err) end - end end local get_git_branches_upstreams = function() local output = get_os_command_output({ - "git", "for-each-ref", "--format", "'%(refname:short),%(upstream:short)'", "refs/heads" + "git", + "for-each-ref", + "--format", + "'%(refname:short),%(upstream:short)'", + "refs/heads", }) return output end @@ -362,21 +356,20 @@ M.check_branch_upstream = function(branch, upstream) if upstream == nil then upstream_to_check = "" else - upstream_to_check = upstream .. '/' .. branch + upstream_to_check = upstream .. "/" .. branch end local refs = get_git_branches_upstreams() for _, ref in ipairs(refs) do - ref = ref:gsub("'","") - local line = vim.split(ref, ",",true) + ref = ref:gsub("'", "") + local line = vim.split(ref, ",", true) local b = line[1] local u = line[2] if b == branch then correct_branch = true - correct_upstream = ( u == upstream_to_check ) + correct_upstream = (u == upstream_to_check) end - end return correct_branch, correct_upstream @@ -384,7 +377,9 @@ end local get_git_worktrees = function() local output = get_os_command_output({ - "git", "worktree", "list" + "git", + "worktree", + "list", }) return output end @@ -402,7 +397,6 @@ M.check_git_worktree_exists = function(worktree_path) if worktree_path == worktree_line[1] then worktree_exists = true end - end return worktree_exists diff --git a/tests/worktree_spec.lua b/tests/worktree_spec.lua index 4f5e523..11d1431 100644 --- a/tests/worktree_spec.lua +++ b/tests/worktree_spec.lua @@ -1,7 +1,7 @@ -local git_worktree = require('git-worktree') -local Path = require('plenary.path') +local git_worktree = require("git-worktree") +local Path = require("plenary.path") -local harness = require('tests.git_harness') +local harness = require("tests.git_harness") local in_non_git_repo = harness.in_non_git_repo local in_bare_repo_from_origin_no_worktrees = harness.in_bare_repo_from_origin_no_worktrees local in_repo_from_origin_no_worktrees = harness.in_repo_from_origin_no_worktrees @@ -15,8 +15,7 @@ local in_repo_from_origin_2_similar_named_worktrees = harness.in_repo_from_origi local check_git_worktree_exists = harness.check_git_worktree_exists local check_branch_upstream = harness.check_branch_upstream -describe('git-worktree', function() - +describe("git-worktree", function() local completed_create = false local completed_switch = false local completed_delete = false @@ -46,868 +45,727 @@ describe('git-worktree', function() git_worktree.reset() end) - describe('Create', function() - - it('can create a worktree(from origin)(relative path) from a bare repo and switch to it', + describe("Create", function() + it( + "can create a worktree(from origin)(relative path) from a bare repo and switch to it", in_bare_repo_from_origin_no_worktrees(function() - - local branch = "master" - local upstream = "origin" - local path = "master" - git_worktree.create_worktree(path, branch, upstream) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) - - local expected_path = git_worktree:get_root() .. Path.path.sep .. path - -- Check to make sure directory was switched - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - - end)) - - it('can create a worktree(from origin)(absolute path) from a bare repo and switch to it', + local branch = "master" + local upstream = "origin" + local path = "master" + git_worktree.create_worktree(path, branch, upstream) + + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) + + local expected_path = git_worktree:get_root() .. Path.path.sep .. path + -- Check to make sure directory was switched + assert.are.same(expected_path, vim.loop.cwd()) + + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(expected_path)) + + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) + + it( + "can create a worktree(from origin)(absolute path) from a bare repo and switch to it", in_bare_repo_from_origin_no_worktrees(function() - - local branch = "master" - local upstream = "origin" - local path = git_worktree.get_root() .. Path.path.sep .. "master" - git_worktree.create_worktree(path, branch, upstream) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - - end)) - - it('can create a worktree(from origin)(relative path) from a repo and switch to it', + local branch = "master" + local upstream = "origin" + local path = git_worktree.get_root() .. Path.path.sep .. "master" + git_worktree.create_worktree(path, branch, upstream) + + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) + + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), path) + + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(path)) + + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) + + it( + "can create a worktree(from origin)(relative path) from a repo and switch to it", in_repo_from_origin_no_worktrees(function() - - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local branch = "featB" - local upstream = "origin" - local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str - git_worktree.create_worktree(path, branch, upstream) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - local expected_path = Path:new(git_worktree:get_root() .. '/' .. path):normalize() - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - - end)) - - it('can create a worktree(from origin)(absolute path) from a repo and switch to it', + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local branch = "featB" + local upstream = "origin" + local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str + git_worktree.create_worktree(path, branch, upstream) + + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) + + -- Check to make sure directory was switched + local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() + assert.are.same(expected_path, vim.loop.cwd()) + + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(expected_path)) + + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) + + it( + "can create a worktree(from origin)(absolute path) from a repo and switch to it", in_repo_from_origin_no_worktrees(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local branch = "featB" + local upstream = "origin" + local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local branch = "featB" - local upstream = "origin" - local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str + git_worktree.create_worktree(path, branch, upstream) - git_worktree.create_worktree(path, branch, upstream) + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) + -- Check to make sure directory was switched + assert.are.same(path, vim.loop.cwd()) - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(path)) - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - - end)) - - it('can create a worktree(no upstream but detect origin)(relative path) from a bare repo and switch to it', + it( + "can create a worktree(no upstream but detect origin)(relative path) from a bare repo and switch to it", in_bare_repo_from_origin_no_worktrees(function() + local branch = "master" + local upstream = "origin" + local path = "master" + git_worktree.create_worktree(path, branch) - local branch = "master" - local upstream = "origin" - local path = "master" - git_worktree.create_worktree(path, branch) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) - local expected_path = git_worktree:get_root() .. '/' .. path + local expected_path = git_worktree:get_root() .. "/" .. path - -- Check to make sure directory was switched - assert.are.same(expected_path, vim.loop.cwd()) + -- Check to make sure directory was switched + assert.are.same(expected_path, vim.loop.cwd()) - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(expected_path)) - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) - end)) - - it('can create a worktree(no upstream but detect origin)(absolute path) from a bare repo and switch to it', + it( + "can create a worktree(no upstream but detect origin)(absolute path) from a bare repo and switch to it", in_bare_repo_from_origin_no_worktrees(function() + local branch = "master" + local upstream = "origin" + local path = git_worktree:get_root() .. Path.path.sep .. "master" - local branch = "master" - local upstream = "origin" - local path = git_worktree:get_root() .. Path.path.sep .. "master" - - git_worktree.create_worktree(path, branch) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) + git_worktree.create_worktree(path, branch) - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) + -- Check to make sure directory was switched + assert.are.same(path, vim.loop.cwd()) - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(path)) - end)) + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) - it('can create a worktree(no upstream but detect origin)(relative path) from a repo and switch to it', + it( + "can create a worktree(no upstream but detect origin)(relative path) from a repo and switch to it", in_repo_from_origin_no_worktrees(function() - - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local branch = "featB" - local upstream = "origin" - local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str - git_worktree.create_worktree(path, branch) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - local expected_path = Path:new(git_worktree:get_root() .. '/' .. path):normalize() - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - - end)) - - it('can create a worktree(no upstream but detect origin)(absolute path) from a repo and switch to it', + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local branch = "featB" + local upstream = "origin" + local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str + git_worktree.create_worktree(path, branch) + + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) + + -- Check to make sure directory was switched + local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() + assert.are.same(expected_path, vim.loop.cwd()) + + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(expected_path)) + + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) + + it( + "can create a worktree(no upstream but detect origin)(absolute path) from a repo and switch to it", in_repo_from_origin_no_worktrees(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local branch = "featB" + local upstream = "origin" + local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local branch = "featB" - local upstream = "origin" - local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - - git_worktree.create_worktree(path, branch) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) + git_worktree.create_worktree(path, branch) - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) + -- Check to make sure directory was switched + assert.are.same(path, vim.loop.cwd()) - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(path)) - end)) + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) - it('can create a worktree(no upstream no origin)(relative path) from a repo and switch to it', + it( + "can create a worktree(no upstream no origin)(relative path) from a repo and switch to it", in_repo_from_local_no_worktrees(function() - - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local branch = "featB" - local upstream = nil - local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str - git_worktree.create_worktree(path, branch) - - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - local expected_path = Path:new(git_worktree:get_root() .. '/' .. path):normalize() - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - - end)) - - it('can create a worktree(no upstream no origin)(absolute path) from a repo and switch to it', + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local branch = "featB" + local upstream = nil + local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str + git_worktree.create_worktree(path, branch) + + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) + + -- Check to make sure directory was switched + local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() + assert.are.same(expected_path, vim.loop.cwd()) + + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(expected_path)) + + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) + + it( + "can create a worktree(no upstream no origin)(absolute path) from a repo and switch to it", in_repo_from_local_no_worktrees(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local branch = "featB" + local upstream = nil + local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local branch = "featB" - local upstream = nil - local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - - git_worktree.create_worktree(path, branch) + git_worktree.create_worktree(path, branch) - vim.fn.wait( - 10000, - function() - return completed_create and completed_switch - end, - 1000 - ) + vim.fn.wait(10000, function() + return completed_create and completed_switch + end, 1000) - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - - end)) + -- Check to make sure directory was switched + assert.are.same(path, vim.loop.cwd()) + -- Check to make sure it is added to git worktree list + assert.True(check_git_worktree_exists(path)) + -- check to make sure branch/upstream is correct + local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) + assert.True(correct_branch) + assert.True(correct_upstream) + end) + ) end) - describe('Switch', function() - - it('from a bare repo with one worktree, able to switch to worktree (relative path)', + describe("Switch", function() + it( + "from a bare repo with one worktree, able to switch to worktree (relative path)", in_bare_repo_from_origin_1_worktree(function() + local path = "master" + git_worktree.switch_worktree(path) - local path = "master" - git_worktree.switch_worktree(path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - end)) + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) + end) + ) - it('from a bare repo with one worktree, able to switch to worktree (absolute path)', + it( + "from a bare repo with one worktree, able to switch to worktree (absolute path)", in_bare_repo_from_origin_1_worktree(function() + local path = git_worktree:get_root() .. Path.path.sep .. "master" + git_worktree.switch_worktree(path) - local path = git_worktree:get_root() .. Path.path.sep .. "master" - git_worktree.switch_worktree(path) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), path) + end) + ) - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) - - end)) - - it('from a repo with one worktree, able to switch to worktree (relative path)', + it( + "from a repo with one worktree, able to switch to worktree (relative path)", in_repo_from_origin_1_worktree(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local path = "../git_worktree_test_repo_featB_" .. random_str + git_worktree.switch_worktree(path) - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local path = "../git_worktree_test_repo_featB_"..random_str - git_worktree.switch_worktree(path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - local expected_path = Path:new(git_worktree:get_root() .. '/'..path):normalize() + local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), expected_path) + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), expected_path) + end) + ) - end)) - - it('from a repo with one worktree, able to switch to worktree (absolute path)', + it( + "from a repo with one worktree, able to switch to worktree (absolute path)", in_repo_from_origin_1_worktree(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local path = "/tmp/git_worktree_test_repo_featB_" .. random_str + git_worktree.switch_worktree(path) - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local path = "/tmp/git_worktree_test_repo_featB_"..random_str - git_worktree.switch_worktree(path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - end)) + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), path) + end) + ) local get_current_file = function() return vim.api.nvim_buf_get_name(0) end - it('in a featB worktree(bare) with file A open, switch to featC and switch to file A in other worktree', + it( + "in a featB worktree(bare) with file A open, switch to featC and switch to file A in other worktree", in_bare_repo_from_origin_2_worktrees(function() + local featB_path = "featB" + local featB_abs_path = git_worktree:get_root() .. Path.path.sep .. featB_path + local featB_abs_A_path = featB_abs_path .. Path.path.sep .. "A.txt" - local featB_path = "featB" - local featB_abs_path = git_worktree:get_root() .. Path.path.sep .. featB_path - local featB_abs_A_path = featB_abs_path .. Path.path.sep .. "A.txt" - - local featC_path = "featC" - local featC_abs_path = git_worktree:get_root() .. Path.path.sep .. featC_path - local featC_abs_A_path = featC_abs_path .. Path.path.sep .. "A.txt" - - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- open A file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(featB_abs_A_path == get_current_file()) - - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- make sure it switch to file in other tree - assert.True(featC_abs_A_path == get_current_file()) - end)) - - it('in a featB worktree(non bare) with file A open, switch to featC and switch to file A in other worktree', - in_repo_from_origin_2_worktrees(function() + local featC_path = "featC" + local featC_abs_path = git_worktree:get_root() .. Path.path.sep .. featC_path + local featC_abs_A_path = featC_abs_path .. Path.path.sep .. "A.txt" - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - - local featB_path = "../git_worktree_test_repo_featB_"..random_str - local featB_abs_path = "/tmp/git_worktree_test_repo_featB_"..random_str - local featB_abs_A_path = featB_abs_path.."/A.txt" - - local featC_path = "../git_worktree_test_repo_featC_"..random_str - local featC_abs_path = "/tmp/git_worktree_test_repo_featC_"..random_str - local featC_abs_A_path = featC_abs_path.."/A.txt" - - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- open A file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(featB_abs_A_path == get_current_file()) - - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- make sure it switch to file in other tree - assert.True(featC_abs_A_path == get_current_file()) - end)) - - it("in a featB worktree(bare) with file B open, switch to featC and switch to worktree root in other worktree", - in_bare_repo_from_origin_2_worktrees(function() + -- switch to featB worktree + git_worktree.switch_worktree(featB_path) - local featB_path = "featB" - local featB_abs_path = git_worktree:get_root() .. Path.path.sep .. featB_path - local featB_abs_B_path = featB_abs_path .. Path.path.sep .. "B.txt" - - local featC_path = "featC" - local featC_abs_path = git_worktree:get_root() .. Path.path.sep .. featC_path - - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- open B file - vim.cmd("e B.txt") - -- make sure it is opensd - assert.True(featB_abs_B_path == get_current_file()) - - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- make sure it switch to file in other tree - assert.True(featC_abs_path == get_current_file()) - end)) - - it("in a featB worktree(non bare) with file B open, switch to featC and switch to worktree root in other worktree", - in_repo_from_origin_2_worktrees(function() + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) + -- open A file + vim.cmd("e A.txt") + -- make sure it is opensd + assert.True(featB_abs_A_path == get_current_file()) - local featB_path = "../git_worktree_test_repo_featB_"..random_str - local featB_abs_path = "/tmp/git_worktree_test_repo_featB_"..random_str - local featB_abs_B_path = featB_abs_path.."/B.txt" + -- switch to featB worktree + reset_variables() + git_worktree.switch_worktree(featC_path) - local featC_path = "../git_worktree_test_repo_featC_"..random_str - local featC_abs_path = "/tmp/git_worktree_test_repo_featC_"..random_str + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) + -- make sure it switch to file in other tree + assert.True(featC_abs_A_path == get_current_file()) + end) + ) - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) + it( + "in a featB worktree(non bare) with file A open, switch to featC and switch to file A in other worktree", + in_repo_from_origin_2_worktrees(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - -- open A file - vim.cmd("e B.txt") - -- make sure it is opensd - assert.True(featB_abs_B_path == get_current_file()) + local featB_path = "../git_worktree_test_repo_featB_" .. random_str + local featB_abs_path = "/tmp/git_worktree_test_repo_featB_" .. random_str + local featB_abs_A_path = featB_abs_path .. "/A.txt" - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) + local featC_path = "../git_worktree_test_repo_featC_" .. random_str + local featC_abs_path = "/tmp/git_worktree_test_repo_featC_" .. random_str + local featC_abs_A_path = featC_abs_path .. "/A.txt" - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) + -- switch to featB worktree + git_worktree.switch_worktree(featB_path) - -- make sure it switch to file in other tree - assert.True(featC_abs_path == get_current_file()) - end)) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - it('from a bare repo with two worktrees, able to switch to worktree with similar names (relative path)', - in_bare_repo_from_origin_2_similar_named_worktrees(function() + -- open A file + vim.cmd("e A.txt") + -- make sure it is opensd + assert.True(featB_abs_A_path == get_current_file()) - local path1 = "featB" - local path2 = "featB-test" - git_worktree.switch_worktree(path1) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path1) - - -- open A file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(vim.loop.cwd().."/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path2) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path2) - -- Make sure file is switched - assert.True(vim.loop.cwd().."/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path1) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path1) - -- Make sure file is switched - assert.True(vim.loop.cwd().."/A.txt" == get_current_file()) - - end)) - - it('from a bare repo with two worktrees, able to switch to worktree with similar names (absolute path)', - in_bare_repo_from_origin_2_similar_named_worktrees(function() + -- switch to featB worktree + reset_variables() + git_worktree.switch_worktree(featC_path) - local path1 = git_worktree:get_root() .. Path.path.sep .. "featB" - local path2 = git_worktree:get_root() .. Path.path.sep .. "featB-test" - - git_worktree.switch_worktree(path1) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path1) - - -- open B file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(path1.."/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path2) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path2) - -- Make sure file is switched - assert.True(path2.."/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path1) - - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path1) - -- Make sure file is switched - assert.True(path1.."/A.txt" == get_current_file()) - - end)) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - end) - - describe('Delete', function() + -- make sure it switch to file in other tree + assert.True(featC_abs_A_path == get_current_file()) + end) + ) - it('from a bare repo with one worktree, able to delete the worktree (relative path)', - in_bare_repo_from_origin_1_worktree(function() + it( + "in a featB worktree(bare) with file B open, switch to featC and switch to worktree root in other worktree", + in_bare_repo_from_origin_2_worktrees(function() + local featB_path = "featB" + local featB_abs_path = git_worktree:get_root() .. Path.path.sep .. featB_path + local featB_abs_B_path = featB_abs_path .. Path.path.sep .. "B.txt" - local path = "master" - git_worktree.delete_worktree(path) + local featC_path = "featC" + local featC_abs_path = git_worktree:get_root() .. Path.path.sep .. featC_path - vim.fn.wait( - 10000, - function() - return completed_delete - end, - 1000 - ) + -- switch to featB worktree + git_worktree.switch_worktree(featB_path) - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(git_worktree:get_root() .. Path.path.sep .. path)) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + -- open B file + vim.cmd("e B.txt") + -- make sure it is opensd + assert.True(featB_abs_B_path == get_current_file()) - end)) + -- switch to featB worktree + reset_variables() + git_worktree.switch_worktree(featC_path) - it('from a bare repo with one worktree, able to delete the worktree (absolute path)', - in_bare_repo_from_origin_1_worktree(function() + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - local path = git_worktree:get_root() .. Path.path.sep .. "master" - git_worktree.delete_worktree(path) + -- make sure it switch to file in other tree + assert.True(featC_abs_path == get_current_file()) + end) + ) - vim.fn.wait( - 10000, - function() - return completed_delete - end, - 1000 - ) + it( + "in a featB worktree(non bare) with file B open, switch to featC and switch to worktree root in other worktree", + in_repo_from_origin_2_worktrees(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(path)) + local featB_path = "../git_worktree_test_repo_featB_" .. random_str + local featB_abs_path = "/tmp/git_worktree_test_repo_featB_" .. random_str + local featB_abs_B_path = featB_abs_path .. "/B.txt" - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + local featC_path = "../git_worktree_test_repo_featC_" .. random_str + local featC_abs_path = "/tmp/git_worktree_test_repo_featC_" .. random_str - end)) + -- switch to featB worktree + git_worktree.switch_worktree(featB_path) - it('from a repo with one worktree, able to delete the worktree (relative path)', - in_repo_from_origin_1_worktree(function() + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local path = "../git_worktree_test_repo_featB_"..random_str - local absolute_path = "/tmp/git_worktree_test_repo_featB_"..random_str - git_worktree.delete_worktree(path, true) + -- open A file + vim.cmd("e B.txt") + -- make sure it is opensd + assert.True(featB_abs_B_path == get_current_file()) - vim.fn.wait( - 10000, - function() - return completed_delete - end, - 1000 - ) + -- switch to featB worktree + reset_variables() + git_worktree.switch_worktree(featC_path) - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(absolute_path)) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + -- make sure it switch to file in other tree + assert.True(featC_abs_path == get_current_file()) + end) + ) - end)) + it( + "from a bare repo with two worktrees, able to switch to worktree with similar names (relative path)", + in_bare_repo_from_origin_2_similar_named_worktrees(function() + local path1 = "featB" + local path2 = "featB-test" + git_worktree.switch_worktree(path1) + + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + reset_variables() + + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path1) + + -- open A file + vim.cmd("e A.txt") + -- make sure it is opensd + assert.True(vim.loop.cwd() .. "/A.txt" == get_current_file()) + + git_worktree.switch_worktree(path2) + + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + reset_variables() + + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path2) + -- Make sure file is switched + assert.True(vim.loop.cwd() .. "/A.txt" == get_current_file()) + + git_worktree.switch_worktree(path1) + + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path1) + -- Make sure file is switched + assert.True(vim.loop.cwd() .. "/A.txt" == get_current_file()) + end) + ) + + it( + "from a bare repo with two worktrees, able to switch to worktree with similar names (absolute path)", + in_bare_repo_from_origin_2_similar_named_worktrees(function() + local path1 = git_worktree:get_root() .. Path.path.sep .. "featB" + local path2 = git_worktree:get_root() .. Path.path.sep .. "featB-test" - it('from a repo with one worktree, able to delete the worktree (absolute path)', - in_repo_from_origin_1_worktree(function() + git_worktree.switch_worktree(path1) - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local path = "/tmp/git_worktree_test_repo_featB_"..random_str - git_worktree.delete_worktree(path, true) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + reset_variables() - vim.fn.wait( - 10000, - function() - return completed_delete - end, - 1000 - ) + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), path1) - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(path)) + -- open B file + vim.cmd("e A.txt") + -- make sure it is opensd + assert.True(path1 .. "/A.txt" == get_current_file()) - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + git_worktree.switch_worktree(path2) - end)) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + reset_variables() - end) + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), path2) + -- Make sure file is switched + assert.True(path2 .. "/A.txt" == get_current_file()) - describe('Find Git Root Dir / Current Worktree on load', function() + git_worktree.switch_worktree(path1) - it('does not find the paths in a non git repo', - in_non_git_repo(function() + vim.fn.wait(10000, function() + return completed_switch + end, 1000) - git_worktree:setup_git_info() - assert.are.same(nil, git_worktree:get_root()) - assert.are.same(nil, git_worktree:get_current_worktree_path()) + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), path1) + -- Make sure file is switched + assert.True(path1 .. "/A.txt" == get_current_file()) + end) + ) + end) - end)) + describe("Delete", function() + it( + "from a bare repo with one worktree, able to delete the worktree (relative path)", + in_bare_repo_from_origin_1_worktree(function() + local path = "master" + git_worktree.delete_worktree(path) - it('finds the paths in a git repo', - in_repo_from_origin_1_worktree(function() + vim.fn.wait(10000, function() + return completed_delete + end, 1000) - git_worktree:setup_git_info() - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) + -- Check to make sure it is added to git worktree list + assert.False(check_git_worktree_exists(git_worktree:get_root() .. Path.path.sep .. path)) - end)) + -- Check to make sure directory was not switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + end) + ) - it('finds the paths in a bare git repo', + it( + "from a bare repo with one worktree, able to delete the worktree (absolute path)", in_bare_repo_from_origin_1_worktree(function() + local path = git_worktree:get_root() .. Path.path.sep .. "master" + git_worktree.delete_worktree(path) - git_worktree:setup_git_info() - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) - - end)) + vim.fn.wait(10000, function() + return completed_delete + end, 1000) - it('finds the paths from a git repo in a worktree', - in_repo_from_origin_1_worktree(function() + -- Check to make sure it is added to git worktree list + assert.False(check_git_worktree_exists(path)) - local expected_git_repo = git_worktree:get_root() - -- switch to a worktree - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len()-4) - local path = "/tmp/git_worktree_test_repo_featB_"..random_str - git_worktree.switch_worktree(path) + -- Check to make sure directory was not switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + end) + ) - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) - - git_worktree:setup_git_info() - assert.are.same(expected_git_repo, git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) + it( + "from a repo with one worktree, able to delete the worktree (relative path)", + in_repo_from_origin_1_worktree(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local path = "../git_worktree_test_repo_featB_" .. random_str + local absolute_path = "/tmp/git_worktree_test_repo_featB_" .. random_str + git_worktree.delete_worktree(path, true) - end)) + vim.fn.wait(10000, function() + return completed_delete + end, 1000) - it('finds the paths from a bare git repo in a worktree', - in_bare_repo_from_origin_1_worktree(function() + -- Check to make sure it is added to git worktree list + assert.False(check_git_worktree_exists(absolute_path)) - local expected_git_repo = git_worktree:get_root() - -- switch to a worktree - local path = "master" - git_worktree.switch_worktree(path) + -- Check to make sure directory was not switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + end) + ) - vim.fn.wait( - 10000, - function() - return completed_switch - end, - 1000 - ) + it( + "from a repo with one worktree, able to delete the worktree (absolute path)", + in_repo_from_origin_1_worktree(function() + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local path = "/tmp/git_worktree_test_repo_featB_" .. random_str + git_worktree.delete_worktree(path, true) - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) + vim.fn.wait(10000, function() + return completed_delete + end, 1000) - git_worktree:setup_git_info() - assert.are.same(expected_git_repo, git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) + -- Check to make sure it is added to git worktree list + assert.False(check_git_worktree_exists(path)) - end)) + -- Check to make sure directory was not switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + end) + ) end) + describe("Find Git Root Dir / Current Worktree on load", function() + it( + "does not find the paths in a non git repo", + in_non_git_repo(function() + git_worktree:setup_git_info() + assert.are.same(nil, git_worktree:get_root()) + assert.are.same(nil, git_worktree:get_current_worktree_path()) + end) + ) + + it( + "finds the paths in a git repo", + in_repo_from_origin_1_worktree(function() + git_worktree:setup_git_info() + assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) + end) + ) + + it( + "finds the paths in a bare git repo", + in_bare_repo_from_origin_1_worktree(function() + git_worktree:setup_git_info() + assert.are.same(vim.loop.cwd(), git_worktree:get_root()) + assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) + end) + ) + + it( + "finds the paths from a git repo in a worktree", + in_repo_from_origin_1_worktree(function() + local expected_git_repo = git_worktree:get_root() + -- switch to a worktree + local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) + local path = "/tmp/git_worktree_test_repo_featB_" .. random_str + git_worktree.switch_worktree(path) + + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), path) + + git_worktree:setup_git_info() + assert.are.same(expected_git_repo, git_worktree:get_root()) + assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) + end) + ) + + it( + "finds the paths from a bare git repo in a worktree", + in_bare_repo_from_origin_1_worktree(function() + local expected_git_repo = git_worktree:get_root() + -- switch to a worktree + local path = "master" + git_worktree.switch_worktree(path) + + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + + -- Check to make sure directory was switched + assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) + + git_worktree:setup_git_info() + assert.are.same(expected_git_repo, git_worktree:get_root()) + assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) + end) + ) + end) end) From a815edee0f1e44533751653cd2cdb45db862e03d Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 8 Nov 2023 20:57:11 -0500 Subject: [PATCH 06/33] chore: luachecks --- .luacheckrc | 8 ++++++++ flake.nix | 2 +- lua/git-worktree/enum.lua | 2 +- lua/git-worktree/git.lua | 4 ++-- lua/git-worktree/hooks.lua | 17 +++++++++------ lua/git-worktree/init.lua | 24 ++++++++++------------ lua/telescope/_extensions/git_worktree.lua | 2 -- spec/git_spec.lua | 1 + tests/worktree_spec.lua | 5 +++-- 9 files changed, 38 insertions(+), 27 deletions(-) create mode 100644 .luacheckrc diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000..60b5814 --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,8 @@ +ignore = { +} +read_globals = { + "vim", + "describe", + "it", + "assert" +} diff --git a/flake.nix b/flake.nix index 4fee52d..69addd1 100644 --- a/flake.nix +++ b/flake.nix @@ -48,7 +48,7 @@ hooks = { alejandra.enable = true; stylua.enable = true; - #luacheck.enable = true; + luacheck.enable = true; #markdownlint.enable = true; }; }; diff --git a/lua/git-worktree/enum.lua b/lua/git-worktree/enum.lua index d58150a..9a6e59f 100644 --- a/lua/git-worktree/enum.lua +++ b/lua/git-worktree/enum.lua @@ -4,7 +4,7 @@ local Enum = function(tbl) error(string.format("%s does not exist for this enum.", key)) end, - __newindex = function(t, key, value) + __newindex = function(_, _, _) error("Enums are immutable. You are not able to set new values") end, }) diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index d0d323c..04fca66 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -1,5 +1,5 @@ local Job = require("plenary").job -local Path = require("plenary.path") +--local Path = require("plenary.path") local Status = require("git-worktree.status") local status = Status:new() @@ -55,7 +55,7 @@ function M.is_worktree() end end ---- @param is_worktree boolean +-- @param is_worktree boolean --- @return string|nil function M.find_git_dir() local job = Job:new({ diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 6f9718e..13c9ec7 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -1,7 +1,11 @@ +local Enum = require("git-worktree.enum") +local Status = require("git-worktree.status") +local status = Status:new() + --- @class GitWorktreeHooks local M = {} -local function on_tree_change_handler(op, metadata) +function M.on_tree_change_handler(op, metadata) if M._config.update_on_change then if op == Enum.Operations.Switch then local changed = M.update_current_buffer(metadata["prev_path"]) @@ -15,13 +19,14 @@ local function on_tree_change_handler(op, metadata) end end -local function emit_on_change(op, metadata) +function M.emit_on_change(op, metadata) -- TODO: We don't have a way to async update what is running status:next_status(string.format("Running post %s callbacks", op)) - on_tree_change_handler(op, metadata) - for idx = 1, #on_change_callbacks do - on_change_callbacks[idx](op, metadata) - end + print(metadata) + -- on_tree_change_handler(op, metadata) + -- for idx = 1, #on_change_callbacks do + -- on_change_callbacks[idx](op, metadata) + -- end end return M diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index 0dc0120..af9faf9 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -3,6 +3,8 @@ local Path = require("plenary.path") local Enum = require("git-worktree.enum") local Status = require("git-worktree.status") +local Hooks = require("git-worktree.hooks") +local Git = require("git-worktree.git") local status = Status:new() local M = {} @@ -196,14 +198,14 @@ local function create_worktree(path, branch, upstream, found_branch) end vim.schedule(function() - emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) + Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) M.switch_worktree(path) end) end) else create:after(function() vim.schedule(function() - emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) + Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) M.switch_worktree(path) end) end) @@ -216,7 +218,7 @@ M.create_worktree = function(path, branch, upstream) status:reset(8) if upstream == nil then - if has_origin() then + if Git.has_origin() then upstream = "origin" end end @@ -228,7 +230,7 @@ M.create_worktree = function(path, branch, upstream) status:error("worktree already exists") end - has_branch(branch, function(found_branch) + Git.has_branch(branch, function(found_branch) create_worktree(path, branch, upstream, found_branch) end) end) @@ -244,7 +246,7 @@ M.switch_worktree = function(path) vim.schedule(function() local prev_path = change_dirs(path) - emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) + Hooks.emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) end) end) end @@ -274,7 +276,7 @@ M.delete_worktree = function(path, force, opts) local delete = Job:new(cmd) delete:after_success(vim.schedule_wrap(function() - emit_on_change(Enum.Operations.Delete, { path = path }) + Hooks.emit_on_change(Enum.Operations.Delete, { path = path }) if opts.on_success then opts.on_success() end @@ -313,12 +315,12 @@ M.update_current_buffer = function(prev_path) end local name = Path:new(current_buf_name):absolute() - local start, fin = string.find(name, cwd .. Path.path.sep, 1, true) - if start ~= nil then + local start1, _ = string.find(name, cwd .. Path.path.sep, 1, true) + if start1 ~= nil then return true end - start, fin = string.find(name, prev_path, 1, true) + local start, fin = string.find(name, prev_path, 1, true) if start == nil then return false end @@ -374,10 +376,6 @@ M.setup = function(config) }, config) end -M.set_status = function(msg) - -- TODO: make this so #1 -end - M.setup() M.Operations = Enum.Operations diff --git a/lua/telescope/_extensions/git_worktree.lua b/lua/telescope/_extensions/git_worktree.lua index 33c7720..a044f15 100644 --- a/lua/telescope/_extensions/git_worktree.lua +++ b/lua/telescope/_extensions/git_worktree.lua @@ -1,5 +1,3 @@ -local Path = require("plenary.path") -local Window = require("plenary.window.float") local strings = require("plenary.strings") local pickers = require("telescope.pickers") local finders = require("telescope.finders") diff --git a/spec/git_spec.lua b/spec/git_spec.lua index 1b23045..043452c 100644 --- a/spec/git_spec.lua +++ b/spec/git_spec.lua @@ -4,6 +4,7 @@ local Status = require("git-worktree.status") local status = Status:new() +-- luacheck: globals repo_dir describe("git-worktree git operations", function() describe("finds git toplevel in normal repo", function() before_each(function() diff --git a/tests/worktree_spec.lua b/tests/worktree_spec.lua index 11d1431..d3b96b8 100644 --- a/tests/worktree_spec.lua +++ b/tests/worktree_spec.lua @@ -11,7 +11,7 @@ local in_repo_from_local_no_worktrees = harness.in_repo_from_local_no_worktrees local in_bare_repo_from_origin_2_worktrees = harness.in_bare_repo_from_origin_2_worktrees local in_repo_from_origin_2_worktrees = harness.in_repo_from_origin_2_worktrees local in_bare_repo_from_origin_2_similar_named_worktrees = harness.in_bare_repo_from_origin_2_similar_named_worktrees -local in_repo_from_origin_2_similar_named_worktrees = harness.in_repo_from_origin_2_similar_named_worktrees +--local in_repo_from_origin_2_similar_named_worktrees = harness.in_repo_from_origin_2_similar_named_worktrees local check_git_worktree_exists = harness.check_git_worktree_exists local check_branch_upstream = harness.check_branch_upstream @@ -492,7 +492,8 @@ describe("git-worktree", function() ) it( - "in a featB worktree(non bare) with file B open, switch to featC and switch to worktree root in other worktree", + "in a featB worktree(non bare) with file B open, switch to featC and switch to worktree" + .. " root in other worktree", in_repo_from_origin_2_worktrees(function() local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) From 2a2c92aea331a0ce41f419ee42db8fd9f70567cf Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 9 Nov 2023 23:43:23 -0500 Subject: [PATCH 07/33] refactor: stylua fixes and start to build from core --- .luacheckrc | 2 + .stylua.toml | 6 + flake.nix | 42 +- lua/git-worktree/config.lua | 33 + lua/git-worktree/enum.lua | 41 +- lua/git-worktree/git.lua | 267 +++---- lua/git-worktree/hooks.lua | 52 +- lua/git-worktree/init.lua | 762 ++++++++++---------- lua/git-worktree/status.lua | 47 +- lua/git-worktree/test.lua | 4 - lua/telescope/_extensions/git_worktree.lua | 456 ++++++------ spec/git_spec.lua | 27 +- spec/setup_spec.lua | 4 +- spec/util/git_harness.lua | 26 +- spec/util/system.lua | 12 +- tests/git_harness.lua | 405 ----------- tests/minimal_init.vim | 4 - tests/worktree_spec.lua | 772 --------------------- 18 files changed, 934 insertions(+), 2028 deletions(-) create mode 100644 .stylua.toml delete mode 100644 lua/git-worktree/test.lua delete mode 100644 tests/git_harness.lua delete mode 100644 tests/minimal_init.vim delete mode 100644 tests/worktree_spec.lua diff --git a/.luacheckrc b/.luacheckrc index 60b5814..fc60a60 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1,3 +1,5 @@ +self = false + ignore = { } read_globals = { diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000..5f0d0aa --- /dev/null +++ b/.stylua.toml @@ -0,0 +1,6 @@ +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 4 +quote_style = "AutoPreferSingle" +call_parentheses = "NoSingleTable" +collapse_simple_statement = "Never" diff --git a/flake.nix b/flake.nix index 69addd1..70d84b8 100644 --- a/flake.nix +++ b/flake.nix @@ -64,17 +64,19 @@ name = "haskell-tools.nvim-shell"; inherit (pre-commit-check) shellHook; buildInputs = - (with pkgs; [ + with pkgs; [ neorocks haskellPackages.neolua-bin - ]) - ++ (with inputs.pre-commit-hooks.packages.${system}; [ - alejandra - lua-language-server stylua - luacheck - markdownlint-cli - ]); + ] + #++ (with inputs.pre-commit-hooks.packages.${system}; [ + # alejandra + # lua-language-server + # stylua + # luacheck + # markdownlint-cli + #]) + ; LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath []; }; }; @@ -100,18 +102,18 @@ checks = { inherit pre-commit-check; - # type-check-stable = pkgs.callPackage ./nix/type-check.nix { - # stable = true; - # inherit (config.packages) neodev-plugin telescope-plugin; - # inherit (inputs) pre-commit-hooks; - # inherit self; - # }; - # type-check-nightly = pkgs.callPackage ./nix/type-check.nix { - # stable = false; - # inherit (config.packages) neodev-plugin telescope-plugin; - # inherit (inputs) pre-commit-hooks; - # inherit self; - # }; + type-check-stable = pkgs.callPackage ./nix/type-check.nix { + stable = true; + inherit (config.packages) neodev-plugin telescope-plugin; + inherit (inputs) pre-commit-hooks; + inherit self; + }; + type-check-nightly = pkgs.callPackage ./nix/type-check.nix { + stable = false; + inherit (config.packages) neodev-plugin telescope-plugin; + inherit (inputs) pre-commit-hooks; + inherit self; + }; neorocks-test-stable = pkgs.callPackage ./nix/neorocks-test.nix { name = "git-worktree-stable"; inherit self; diff --git a/lua/git-worktree/config.lua b/lua/git-worktree/config.lua index 5044d6f..c2ecbb7 100644 --- a/lua/git-worktree/config.lua +++ b/lua/git-worktree/config.lua @@ -1,3 +1,36 @@ local M = {} +---@class GitWorktreeConfig + +---@class GitWorktreePartialConfig +---@field change_directory_command? string +---@field update_on_change? boolean +---@field update_on_change_command? string +---@field clearjumps_on_change? boolean +---@field confirm_telescope_deletions? boolean +---@field autopush? boolean + +---@return GitWorktreeConfig +function M.get_default_config() + return { + change_directory_command = 'cd', + update_on_change = true, + update_on_change_command = 'e .', + clearjumps_on_change = true, + confirm_telescope_deletions = true, + autopush = false, + } +end + +---@param partial_config GitWorktreePartialConfig +---@param latest_config GitWorktreeConfig? +---@return GitWorktreeConfig +function M.merge_config(partial_config, latest_config) + local config = latest_config or M.get_default_config() + + config = vim.tbl_extend('force', config, partial_config) + + return config +end + return M diff --git a/lua/git-worktree/enum.lua b/lua/git-worktree/enum.lua index 9a6e59f..47ab23a 100644 --- a/lua/git-worktree/enum.lua +++ b/lua/git-worktree/enum.lua @@ -1,19 +1,22 @@ -local Enum = function(tbl) - return setmetatable(tbl, { - __index = function(_, key) - error(string.format("%s does not exist for this enum.", key)) - end, - - __newindex = function(_, _, _) - error("Enums are immutable. You are not able to set new values") - end, - }) -end - -return { - Operations = Enum({ - Create = "create", - Switch = "switch", - Delete = "delete", - }), -} +-- --- @class GitWorktreeOperation +-- +-- --- @return GitWorktreeOperation: A enum reperesenting worktree operation being performed +-- local Enum = function(tbl) +-- return setmetatable(tbl, { +-- __index = function(_, key) +-- error(string.format("%s does not exist for this enum.", key)) +-- end, +-- +-- __newindex = function(_, _, _) +-- error("Enums are immutable. You are not able to set new values") +-- end, +-- }) +-- end +-- +-- return { +-- Operation = Enum({ +-- Create = "create", +-- Switch = "switch", +-- Delete = "delete", +-- }), +-- } diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index 04fca66..c890939 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -1,88 +1,88 @@ -local Job = require("plenary").job ---local Path = require("plenary.path") -local Status = require("git-worktree.status") - -local status = Status:new() - +local Job = require('plenary').job +-- --local Path = require("plenary.path") +-- local Status = require("git-worktree.status") +-- +-- local status = Status:new() +-- ---@class GitWorktreeGitOps local M = {} - ---- @return boolean -function M.is_bare_repo() - local inside_worktree_job = Job:new({ - "git", - "rev-parse", - "--is-bare-repository", - cwd = vim.loop.cwd(), - }) - - local stdout, code = inside_worktree_job:sync() - if code ~= 0 then - status:log().error("Error in determining if we are in a worktree") - return false - end - - stdout = table.concat(stdout, "") - - if stdout == "true" then - return true - else - return false - end -end - ---- @return boolean -function M.is_worktree() - local inside_worktree_job = Job:new({ - "git", - "rev-parse", - "--is-inside-work-tree", - cwd = vim.loop.cwd(), - }) - - local stdout, code = inside_worktree_job:sync() - if code ~= 0 then - status:log().error("Error in determining if we are in a worktree") - return false - end - - stdout = table.concat(stdout, "") - - if stdout == "true" then - return true - else - return false - end -end - +-- +-- --- @return boolean +-- function M.is_bare_repo() +-- local inside_worktree_job = Job:new({ +-- "git", +-- "rev-parse", +-- "--is-bare-repository", +-- cwd = vim.loop.cwd(), +-- }) +-- +-- local stdout, code = inside_worktree_job:sync() +-- if code ~= 0 then +-- status:log().error("Error in determining if we are in a worktree") +-- return false +-- end +-- +-- stdout = table.concat(stdout, "") +-- +-- if stdout == "true" then +-- return true +-- else +-- return false +-- end +-- end +-- +-- --- @return boolean +-- function M.is_worktree() +-- local inside_worktree_job = Job:new({ +-- "git", +-- "rev-parse", +-- "--is-inside-work-tree", +-- cwd = vim.loop.cwd(), +-- }) +-- +-- local stdout, code = inside_worktree_job:sync() +-- if code ~= 0 then +-- status:log().error("Error in determining if we are in a worktree") +-- return false +-- end +-- +-- stdout = table.concat(stdout, "") +-- +-- if stdout == "true" then +-- return true +-- else +-- return false +-- end +-- end +-- -- @param is_worktree boolean --- @return string|nil function M.find_git_dir() - local job = Job:new({ - "git", - "rev-parse", - "--show-toplevel", + local job = Job:new { + 'git', + 'rev-parse', + '--show-toplevel', cwd = vim.loop.cwd(), - on_stderr = function(_, data) - status:log().info("ERROR: " .. data) - end, - }) + -- on_stderr = function(_, data) + -- status:log().info('ERROR: ' .. data) + -- end, + } local stdout, code = job:sync() if code ~= 0 then - status:log().error( - "Error in determining the git root dir: code:" - .. tostring(code) - .. " out: " - .. table.concat(stdout, "") - .. "." - ) + -- status:log().error( + -- 'Error in determining the git root dir: code:' + -- .. tostring(code) + -- .. ' out: ' + -- .. table.concat(stdout, '') + -- .. '.' + -- ) return nil end - stdout = table.concat(stdout, "") - status:log().info("cwd: " .. vim.loop.cwd()) - status:log().info("git root dir: " .. stdout) + stdout = table.concat(stdout, '') + -- status:log().info('cwd: ' .. vim.loop.cwd()) + -- status:log().info('git root dir: ' .. stdout) -- if is_worktree then -- -- if in worktree git dir returns absolute path @@ -117,64 +117,65 @@ function M.find_git_dir() -- end end ---- @return string|nil -function M.find_git_toplevel() - local find_toplevel_job = Job:new({ - "git", - "rev-parse", - "--show-toplevel", - cwd = vim.loop.cwd(), - }) - local stdout, code = find_toplevel_job:sync() - if code == 0 then - stdout = table.concat(stdout, "") - return stdout - else - return nil - end -end - -function M.has_branch(branch, cb) - local found = false - local job = Job:new({ - "git", - "branch", - on_stdout = function(_, data) - -- remove markere on current branch - data = data:gsub("*", "") - data = vim.trim(data) - found = found or data == branch - end, - cwd = vim.loop.cwd(), - }) - - -- TODO: I really don't want status's spread everywhere... seems bad - status:next_status(string.format("Checking for branch %s", branch)) - job:after(function() - status:status("found branch: " .. tostring(found)) - cb(found) - end):start() -end - -function M.has_origin() - local found = false - local job = Job:new({ - "git", - "remote", - "show", - on_stdout = function(_, data) - data = vim.trim(data) - found = found or data == "origin" - end, - cwd = vim.loop.cwd(), - }) - - -- TODO: I really don't want status's spread everywhere... seems bad - job:after(function() - status:status("found origin: " .. tostring(found)) - end):sync() - - return found -end - +-- +-- --- @return string|nil +-- function M.find_git_toplevel() +-- local find_toplevel_job = Job:new({ +-- "git", +-- "rev-parse", +-- "--show-toplevel", +-- cwd = vim.loop.cwd(), +-- }) +-- local stdout, code = find_toplevel_job:sync() +-- if code == 0 then +-- stdout = table.concat(stdout, "") +-- return stdout +-- else +-- return nil +-- end +-- end +-- +-- function M.has_branch(branch, cb) +-- local found = false +-- local job = Job:new({ +-- "git", +-- "branch", +-- on_stdout = function(_, data) +-- -- remove markere on current branch +-- data = data:gsub("*", "") +-- data = vim.trim(data) +-- found = found or data == branch +-- end, +-- cwd = vim.loop.cwd(), +-- }) +-- +-- -- TODO: I really don't want status's spread everywhere... seems bad +-- status:next_status(string.format("Checking for branch %s", branch)) +-- job:after(function() +-- status:status("found branch: " .. tostring(found)) +-- cb(found) +-- end):start() +-- end +-- +-- function M.has_origin() +-- local found = false +-- local job = Job:new({ +-- "git", +-- "remote", +-- "show", +-- on_stdout = function(_, data) +-- data = vim.trim(data) +-- found = found or data == "origin" +-- end, +-- cwd = vim.loop.cwd(), +-- }) +-- +-- -- TODO: I really don't want status's spread everywhere... seems bad +-- job:after(function() +-- status:status("found origin: " .. tostring(found)) +-- end):sync() +-- +-- return found +-- end +-- return M diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 13c9ec7..495fa54 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -1,32 +1,34 @@ -local Enum = require("git-worktree.enum") -local Status = require("git-worktree.status") -local status = Status:new() +-- local Enum = require("git-worktree.enum") +-- local Status = require("git-worktree.status") +-- local status = Status:new() --- @class GitWorktreeHooks + local M = {} -function M.on_tree_change_handler(op, metadata) - if M._config.update_on_change then - if op == Enum.Operations.Switch then - local changed = M.update_current_buffer(metadata["prev_path"]) - if not changed then - status - :log() - .debug("Could not change to the file in the new worktree, running the `update_on_change_command`") - vim.cmd(M._config.update_on_change_command) - end - end - end -end +-- function M.on_tree_change_handler(op, metadata) +-- if M._config.update_on_change then +-- if op == Enum.Operations.Switch then +-- local changed = M.update_current_buffer(metadata["prev_path"]) +-- if not changed then +-- status +-- :log() +-- .debug("Could not change to the file in the new worktree, +-- running the `update_on_change_command`") +-- vim.cmd(M._config.update_on_change_command) +-- end +-- end +-- end +-- end -function M.emit_on_change(op, metadata) - -- TODO: We don't have a way to async update what is running - status:next_status(string.format("Running post %s callbacks", op)) - print(metadata) - -- on_tree_change_handler(op, metadata) - -- for idx = 1, #on_change_callbacks do - -- on_change_callbacks[idx](op, metadata) - -- end -end +-- function M.emit_on_change(op, metadata) +-- -- TODO: We don't have a way to async update what is running +-- status:next_status(string.format("Running post %s callbacks", op)) +-- print(metadata) +-- -- on_tree_change_handler(op, metadata) +-- -- for idx = 1, #on_change_callbacks do +-- -- on_change_callbacks[idx](op, metadata) +-- -- end +-- end return M diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index af9faf9..b3964b2 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -1,382 +1,408 @@ -local Job = require("plenary.job") -local Path = require("plenary.path") -local Enum = require("git-worktree.enum") +-- local Job = require("plenary.job") +-- local Path = require("plenary.path") +-- local Enum = require("git-worktree.enum") -local Status = require("git-worktree.status") -local Hooks = require("git-worktree.hooks") -local Git = require("git-worktree.git") +local Config = require('git-worktree.config') +-- local Git = require("git-worktree.git") +-- local Hooks = require("git-worktree.hooks") +local Status = require('git-worktree.status') local status = Status:new() -local M = {} -local git_worktree_root = nil -local current_worktree_path = nil -local on_change_callbacks = {} - -local function change_dirs(path) - local worktree_path = M.get_worktree_path(path) - - local previous_worktree = current_worktree_path - - -- vim.loop.chdir(worktree_path) - if Path:new(worktree_path):exists() then - local cmd = string.format("%s %s", M._config.change_directory_command, worktree_path) - status:log().debug("Changing to directory " .. worktree_path) - vim.cmd(cmd) - current_worktree_path = worktree_path - else - status:error("Could not chang to directory: " .. worktree_path) - end - - if M._config.clearjumps_on_change then - status:log().debug("Clearing jumps") - vim.cmd("clearjumps") - end - - return previous_worktree -end - -local function create_worktree_job(path, branch, found_branch) - local worktree_add_cmd = "git" - local worktree_add_args = { "worktree", "add" } - - if not found_branch then - table.insert(worktree_add_args, "-b") - table.insert(worktree_add_args, branch) - table.insert(worktree_add_args, path) - else - table.insert(worktree_add_args, path) - table.insert(worktree_add_args, branch) - end - - return Job:new({ - command = worktree_add_cmd, - args = worktree_add_args, - cwd = git_worktree_root, - on_start = function() - status:next_status(worktree_add_cmd .. " " .. table.concat(worktree_add_args, " ")) - end, - }) -end - --- A lot of this could be cleaned up if there was better job -> job -> function --- communication. That should be doable here in the near future -local function has_worktree(path, cb) - local found = false - local plenary_path = Path:new(path) - - local job = Job:new({ - "git", - "worktree", - "list", - on_stdout = function(_, data) - local list_data = {} - for section in data:gmatch("%S+") do - table.insert(list_data, section) - end - - data = list_data[1] - - local start - if plenary_path:is_absolute() then - start = data == path - else - local worktree_path = Path:new(string.format("%s" .. Path.path.sep .. "%s", git_worktree_root, path)) - worktree_path = worktree_path:absolute() - start = data == worktree_path - end - - -- TODO: This is clearly a hack (do not think we need this anymore?) - local start_with_head = string.find(data, string.format("[heads/%s]", path), 1, true) - found = found or start or start_with_head - end, - cwd = git_worktree_root, - }) - - job:after(function() - cb(found) - end) - - -- TODO: I really don't want status's spread everywhere... seems bad - status:next_status("Checking for worktree " .. path) - job:start() -end +-- local git_worktree_root = nil +-- local current_worktree_path = nil +-- local on_change_callbacks = {} -local function failure(from, cmd, path, soft_error) - return function(e) - local error_message = string.format( - "%s Failed: PATH %s CMD %s RES %s, ERR %s", - from, - path, - vim.inspect(cmd), - vim.inspect(e:result()), - vim.inspect(e:stderr_result()) - ) +---@class GitWorktree +---@field config GitWorktreeConfig - if soft_error then - status:status(error_message) - else - status:error(error_message) - end - end -end - -local function create_worktree(path, branch, upstream, found_branch) - local create = create_worktree_job(path, branch, found_branch) - - local worktree_path - if Path:new(path):is_absolute() then - worktree_path = path - else - worktree_path = Path:new(git_worktree_root, path):absolute() - end - - local fetch = Job:new({ - "git", - "fetch", - "--all", - cwd = worktree_path, - on_start = function() - status:next_status("git fetch --all (This may take a moment)") - end, - }) - - local set_branch_cmd = "git" - local set_branch_args = { "branch", string.format("--set-upstream-to=%s/%s", upstream, branch) } - local set_branch = Job:new({ - command = set_branch_cmd, - args = set_branch_args, - cwd = worktree_path, - on_start = function() - status:next_status(set_branch_cmd .. " " .. table.concat(set_branch_args, " ")) - end, - }) - - -- TODO: How to configure origin??? Should upstream ever be the push - -- destination? - local set_push_cmd = "git" - local set_push_args = { "push", "--set-upstream", upstream, branch, path } - local set_push = Job:new({ - command = set_push_cmd, - args = set_push_args, - cwd = worktree_path, - on_start = function() - status:next_status(set_push_cmd .. " " .. table.concat(set_push_args, " ")) - end, - }) - - local rebase = Job:new({ - "git", - "rebase", - cwd = worktree_path, - on_start = function() - status:next_status("git rebase") - end, - }) - - if upstream ~= nil then - create:and_then_on_success(fetch) - fetch:and_then_on_success(set_branch) - - if M._config.autopush then - -- These are "optional" operations. - -- We have to figure out how we want to handle these... - set_branch:and_then(set_push) - set_push:and_then(rebase) - set_push:after_failure(failure("create_worktree", set_branch.args, worktree_path, true)) - else - set_branch:and_then(rebase) - end - - create:after_failure(failure("create_worktree", create.args, git_worktree_root)) - fetch:after_failure(failure("create_worktree", fetch.args, worktree_path)) - - set_branch:after_failure(failure("create_worktree", set_branch.args, worktree_path, true)) - - rebase:after(function() - if rebase.code ~= 0 then - status:status("Rebase failed, but that's ok.") - end +local M = {} - vim.schedule(function() - Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) - M.switch_worktree(path) - end) - end) - else - create:after(function() - vim.schedule(function() - Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) - M.switch_worktree(path) - end) - end) - end +M.__index = M - create:start() +---@return GitWorktree +function M:new() + local config = Config.get_default_config() + return setmetatable({ + config = config, + }, self) end -M.create_worktree = function(path, branch, upstream) - status:reset(8) - - if upstream == nil then - if Git.has_origin() then - upstream = "origin" - end - end - - M.setup_git_info() - - has_worktree(path, function(found) - if found then - status:error("worktree already exists") - end - - Git.has_branch(branch, function(found_branch) - create_worktree(path, branch, upstream, found_branch) - end) - end) +---@param partial_config GitWorktreePartialConfig +---@return GitWorktree +function M:setup(partial_config) + self.config = Config.merge_config(partial_config, self.config) + return self end +-- local function change_dirs(path) +-- local worktree_path = M.get_worktree_path(path) +-- +-- local previous_worktree = current_worktree_path +-- +-- -- vim.loop.chdir(worktree_path) +-- if Path:new(worktree_path):exists() then +-- local cmd = string.format("%s %s", M._config.change_directory_command, worktree_path) +-- status:log().debug("Changing to directory " .. worktree_path) +-- vim.cmd(cmd) +-- current_worktree_path = worktree_path +-- else +-- status:error("Could not chang to directory: " .. worktree_path) +-- end +-- +-- if M._config.clearjumps_on_change then +-- status:log().debug("Clearing jumps") +-- vim.cmd("clearjumps") +-- end +-- +-- return previous_worktree +-- end +-- +-- local function create_worktree_job(path, branch, found_branch) +-- local worktree_add_cmd = "git" +-- local worktree_add_args = { "worktree", "add" } +-- +-- if not found_branch then +-- table.insert(worktree_add_args, "-b") +-- table.insert(worktree_add_args, branch) +-- table.insert(worktree_add_args, path) +-- else +-- table.insert(worktree_add_args, path) +-- table.insert(worktree_add_args, branch) +-- end +-- +-- return Job:new({ +-- command = worktree_add_cmd, +-- args = worktree_add_args, +-- cwd = git_worktree_root, +-- on_start = function() +-- status:next_status(worktree_add_cmd .. " " .. table.concat(worktree_add_args, " ")) +-- end, +-- }) +-- end +-- +-- -- A lot of this could be cleaned up if there was better job -> job -> function +-- -- communication. That should be doable here in the near future +-- local function has_worktree(path, cb) +-- local found = false +-- local plenary_path = Path:new(path) +-- +-- local job = Job:new({ +-- "git", +-- "worktree", +-- "list", +-- on_stdout = function(_, data) +-- local list_data = {} +-- for section in data:gmatch("%S+") do +-- table.insert(list_data, section) +-- end +-- +-- data = list_data[1] +-- +-- local start +-- if plenary_path:is_absolute() then +-- start = data == path +-- else +-- local worktree_path = Path:new(string.format("%s" .. Path.path.sep .. "%s", git_worktree_root, path)) +-- worktree_path = worktree_path:absolute() +-- start = data == worktree_path +-- end +-- +-- -- TODO: This is clearly a hack (do not think we need this anymore?) +-- local start_with_head = string.find(data, string.format("[heads/%s]", path), 1, true) +-- found = found or start or start_with_head +-- end, +-- cwd = git_worktree_root, +-- }) +-- +-- job:after(function() +-- cb(found) +-- end) +-- +-- -- TODO: I really don't want status's spread everywhere... seems bad +-- status:next_status("Checking for worktree " .. path) +-- job:start() +-- end +-- +-- local function failure(from, cmd, path, soft_error) +-- return function(e) +-- local error_message = string.format( +-- "%s Failed: PATH %s CMD %s RES %s, ERR %s", +-- from, +-- path, +-- vim.inspect(cmd), +-- vim.inspect(e:result()), +-- vim.inspect(e:stderr_result()) +-- ) +-- +-- if soft_error then +-- status:status(error_message) +-- else +-- status:error(error_message) +-- end +-- end +-- end +-- +-- local function create_worktree(path, branch, upstream, found_branch) +-- local create = create_worktree_job(path, branch, found_branch) +-- +-- local worktree_path +-- if Path:new(path):is_absolute() then +-- worktree_path = path +-- else +-- worktree_path = Path:new(git_worktree_root, path):absolute() +-- end +-- +-- local fetch = Job:new({ +-- "git", +-- "fetch", +-- "--all", +-- cwd = worktree_path, +-- on_start = function() +-- status:next_status("git fetch --all (This may take a moment)") +-- end, +-- }) +-- +-- local set_branch_cmd = "git" +-- local set_branch_args = { "branch", string.format("--set-upstream-to=%s/%s", upstream, branch) } +-- local set_branch = Job:new({ +-- command = set_branch_cmd, +-- args = set_branch_args, +-- cwd = worktree_path, +-- on_start = function() +-- status:next_status(set_branch_cmd .. " " .. table.concat(set_branch_args, " ")) +-- end, +-- }) +-- +-- -- TODO: How to configure origin??? Should upstream ever be the push +-- -- destination? +-- local set_push_cmd = "git" +-- local set_push_args = { "push", "--set-upstream", upstream, branch, path } +-- local set_push = Job:new({ +-- command = set_push_cmd, +-- args = set_push_args, +-- cwd = worktree_path, +-- on_start = function() +-- status:next_status(set_push_cmd .. " " .. table.concat(set_push_args, " ")) +-- end, +-- }) +-- +-- local rebase = Job:new({ +-- "git", +-- "rebase", +-- cwd = worktree_path, +-- on_start = function() +-- status:next_status("git rebase") +-- end, +-- }) +-- +-- if upstream ~= nil then +-- create:and_then_on_success(fetch) +-- fetch:and_then_on_success(set_branch) +-- +-- if M._config.autopush then +-- -- These are "optional" operations. +-- -- We have to figure out how we want to handle these... +-- set_branch:and_then(set_push) +-- set_push:and_then(rebase) +-- set_push:after_failure(failure("create_worktree", set_branch.args, worktree_path, true)) +-- else +-- set_branch:and_then(rebase) +-- end +-- +-- create:after_failure(failure("create_worktree", create.args, git_worktree_root)) +-- fetch:after_failure(failure("create_worktree", fetch.args, worktree_path)) +-- +-- set_branch:after_failure(failure("create_worktree", set_branch.args, worktree_path, true)) +-- +-- rebase:after(function() +-- if rebase.code ~= 0 then +-- status:status("Rebase failed, but that's ok.") +-- end +-- +-- vim.schedule(function() +-- Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) +-- M.switch_worktree(path) +-- end) +-- end) +-- else +-- create:after(function() +-- vim.schedule(function() +-- Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) +-- M.switch_worktree(path) +-- end) +-- end) +-- end +-- +-- create:start() +-- end +-- +-- M.create_worktree = function(path, branch, upstream) +-- status:reset(8) +-- +-- if upstream == nil then +-- if Git.has_origin() then +-- upstream = "origin" +-- end +-- end +-- +-- M.setup_git_info() +-- +-- has_worktree(path, function(found) +-- if found then +-- status:error("worktree already exists") +-- end +-- +-- Git.has_branch(branch, function(found_branch) +-- create_worktree(path, branch, upstream, found_branch) +-- end) +-- end) +-- end +-- + +--Switch the current worktree +---@param path string M.switch_worktree = function(path) status:reset(2) - M.setup_git_info() - has_worktree(path, function(found) - if not found then - status:error("worktree does not exists, please create it first " .. path) - end - - vim.schedule(function() - local prev_path = change_dirs(path) - Hooks.emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) - end) - end) + status:status(path) + -- M.setup_git_info() + -- has_worktree(path, function(found) + -- if not found then + -- status:error("worktree does not exists, please create it first " .. path) + -- end + -- + -- vim.schedule(function() + -- local prev_path = change_dirs(path) + -- Hooks.emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) + -- end) + -- end) end - -M.delete_worktree = function(path, force, opts) - if not opts then - opts = {} - end - - status:reset(2) - M.setup_git_info() - has_worktree(path, function(found) - if not found then - status:error(string.format("Worktree %s does not exist", path)) - end - - local cmd = { - "git", - "worktree", - "remove", - path, - } - - if force then - table.insert(cmd, "--force") - end - - local delete = Job:new(cmd) - delete:after_success(vim.schedule_wrap(function() - Hooks.emit_on_change(Enum.Operations.Delete, { path = path }) - if opts.on_success then - opts.on_success() - end - end)) - - delete:after_failure(function(e) - -- callback has to be called before failure() because failure() - -- halts code execution - if opts.on_failure then - opts.on_failure(e) - end - - failure(cmd, vim.loop.cwd())(e) - end) - delete:start() - end) -end - -M.set_worktree_root = function(wd) - git_worktree_root = wd -end - -M.set_current_worktree_path = function(wd) - current_worktree_path = wd -end - -M.update_current_buffer = function(prev_path) - if prev_path == nil then - return false - end - - local cwd = vim.loop.cwd() - local current_buf_name = vim.api.nvim_buf_get_name(0) - if not current_buf_name or current_buf_name == "" then - return false - end - - local name = Path:new(current_buf_name):absolute() - local start1, _ = string.find(name, cwd .. Path.path.sep, 1, true) - if start1 ~= nil then - return true - end - - local start, fin = string.find(name, prev_path, 1, true) - if start == nil then - return false - end - - local local_name = name:sub(fin + 2) - - local final_path = Path:new({ cwd, local_name }):absolute() - - if not Path:new(final_path):exists() then - return false - end - - local bufnr = vim.fn.bufnr(final_path, true) - vim.api.nvim_set_current_buf(bufnr) - return true -end - -M.on_tree_change = function(cb) - table.insert(on_change_callbacks, cb) -end - -M.reset = function() - on_change_callbacks = {} -end - -M.get_root = function() - return git_worktree_root -end - -M.get_current_worktree_path = function() - return current_worktree_path -end - -M.get_worktree_path = function(path) - if Path:new(path):is_absolute() then - return path - else - return Path:new(git_worktree_root, path):absolute() - end -end - -M.setup = function(config) - config = config or {} - M._config = vim.tbl_deep_extend("force", { - change_directory_command = "cd", - update_on_change = true, - update_on_change_command = "e .", - clearjumps_on_change = true, - -- default to false to avoid breaking the previous default behavior - confirm_telescope_deletions = false, - -- should this default to true or false? - autopush = false, - }, config) -end - -M.setup() -M.Operations = Enum.Operations - -return M +-- +-- M.delete_worktree = function(path, force, opts) +-- if not opts then +-- opts = {} +-- end +-- +-- status:reset(2) +-- M.setup_git_info() +-- has_worktree(path, function(found) +-- if not found then +-- status:error(string.format("Worktree %s does not exist", path)) +-- end +-- +-- local cmd = { +-- "git", +-- "worktree", +-- "remove", +-- path, +-- } +-- +-- if force then +-- table.insert(cmd, "--force") +-- end +-- +-- local delete = Job:new(cmd) +-- delete:after_success(vim.schedule_wrap(function() +-- Hooks.emit_on_change(Enum.Operations.Delete, { path = path }) +-- if opts.on_success then +-- opts.on_success() +-- end +-- end)) +-- +-- delete:after_failure(function(e) +-- -- callback has to be called before failure() because failure() +-- -- halts code execution +-- if opts.on_failure then +-- opts.on_failure(e) +-- end +-- +-- failure(cmd, vim.loop.cwd())(e) +-- end) +-- delete:start() +-- end) +-- end +-- +-- M.set_worktree_root = function(wd) +-- git_worktree_root = wd +-- end +-- +-- M.set_current_worktree_path = function(wd) +-- current_worktree_path = wd +-- end +-- +-- M.update_current_buffer = function(prev_path) +-- if prev_path == nil then +-- return false +-- end +-- +-- local cwd = vim.loop.cwd() +-- local current_buf_name = vim.api.nvim_buf_get_name(0) +-- if not current_buf_name or current_buf_name == "" then +-- return false +-- end +-- +-- local name = Path:new(current_buf_name):absolute() +-- local start1, _ = string.find(name, cwd .. Path.path.sep, 1, true) +-- if start1 ~= nil then +-- return true +-- end +-- +-- local start, fin = string.find(name, prev_path, 1, true) +-- if start == nil then +-- return false +-- end +-- +-- local local_name = name:sub(fin + 2) +-- +-- local final_path = Path:new({ cwd, local_name }):absolute() +-- +-- if not Path:new(final_path):exists() then +-- return false +-- end +-- +-- local bufnr = vim.fn.bufnr(final_path, true) +-- vim.api.nvim_set_current_buf(bufnr) +-- return true +-- end +-- +-- M.on_tree_change = function(cb) +-- table.insert(on_change_callbacks, cb) +-- end +-- +-- M.reset = function() +-- on_change_callbacks = {} +-- end +-- +-- M.get_root = function() +-- return git_worktree_root +-- end +-- +-- M.get_current_worktree_path = function() +-- return current_worktree_path +-- end +-- +-- M.get_worktree_path = function(path) +-- if Path:new(path):is_absolute() then +-- return path +-- else +-- return Path:new(git_worktree_root, path):absolute() +-- end +-- end +-- +-- M.setup = function(config) +-- config = config or {} +-- M._config = vim.tbl_deep_extend("force", { +-- change_directory_command = "cd", +-- update_on_change = true, +-- update_on_change_command = "e .", +-- clearjumps_on_change = true, +-- -- default to false to avoid breaking the previous default behavior +-- confirm_telescope_deletions = false, +-- -- should this default to true or false? +-- autopush = false, +-- }, config) +-- end +-- +-- M.setup() +-- --M.Operations = Enum.Operations + +return M:new() diff --git a/lua/git-worktree/status.lua b/lua/git-worktree/status.lua index f479659..b917f05 100644 --- a/lua/git-worktree/status.lua +++ b/lua/git-worktree/status.lua @@ -1,7 +1,10 @@ -local Status = {} +---@class GitWorktreeLog +---@field logger any the plenary logging object +local M = {} +---@return string local function set_log_level() - local log_levels = { "trace", "debug", "info", "warn", "error", "fatal" } + local log_levels = { 'trace', 'debug', 'info', 'warn', 'error', 'fatal' } local log_level = vim.env.GIT_WORKTREE_NVIM_LOG or vim.g.git_worktree_log_level for _, level in pairs(log_levels) do @@ -10,16 +13,17 @@ local function set_log_level() end end - return "warn" -- default, if user hasn't set to one from log_levels + return 'warn' -- default, if user hasn't set to one from log_levels end -function Status:new(options) - local obj = vim.tbl_extend("force", { +---@return GitWorktreeLog +function M:new(options) + local obj = vim.tbl_extend('force', { -- What to do here? - logger = require("plenary.log").new({ - plugin = "git-worktree-nvim", + logger = require('plenary.log').new { + plugin = 'git-worktree-nvim', level = set_log_level(), - }), + }, }, options or {}) setmetatable(obj, self) @@ -28,43 +32,52 @@ function Status:new(options) return obj end -function Status:reset(count) +---Resets the count and index on the status logger +--- +---@param count integer +function M:reset(count) self.count = count self.idx = 0 end -function Status:_get_string(msg) - return string.format("%d / %d: %s", self.idx, self.count, msg) +---@param msg string +function M:_get_string(msg) + return string.format('%d / %d: %s', self.idx, self.count, msg) end -function Status:next_status(msg) +---@param msg string +function M:next_status(msg) self.idx = self.idx + 1 local fmt_msg = self:_get_string(msg) print(fmt_msg) self.logger.info(fmt_msg) end -function Status:next_error(msg) +---@param msg string +function M:next_error(msg) self.idx = self.idx + 1 local fmt_msg = self:_get_string(msg) error(fmt_msg) self.logger.error(fmt_msg) end -function Status:status(msg) +---@param msg string +function M:status(msg) local fmt_msg = self:_get_string(msg) print(fmt_msg) self.logger.info(fmt_msg) end -function Status:error(msg) +---@param msg string +function M:error(msg) local fmt_msg = self:_get_string(msg) error(fmt_msg) self.logger.error(fmt_msg) end -function Status:log() +---@return GitWorktreeLog +function M:log() return self.logger end -return Status +return M diff --git a/lua/git-worktree/test.lua b/lua/git-worktree/test.lua deleted file mode 100644 index 3db2700..0000000 --- a/lua/git-worktree/test.lua +++ /dev/null @@ -1,4 +0,0 @@ -local Path = require("plenary.path") -local path = Path:new(vim.loop.cwd(), "foo", "..", "..") - -print(path:absolute()) diff --git a/lua/telescope/_extensions/git_worktree.lua b/lua/telescope/_extensions/git_worktree.lua index a044f15..5cc7862 100644 --- a/lua/telescope/_extensions/git_worktree.lua +++ b/lua/telescope/_extensions/git_worktree.lua @@ -1,230 +1,230 @@ -local strings = require("plenary.strings") -local pickers = require("telescope.pickers") -local finders = require("telescope.finders") -local actions = require("telescope.actions") -local utils = require("telescope.utils") -local action_set = require("telescope.actions.set") -local action_state = require("telescope.actions.state") -local conf = require("telescope.config").values -local git_worktree = require("git-worktree") - -local force_next_deletion = false - -local get_worktree_path = function(prompt_bufnr) - local selection = action_state.get_selected_entry(prompt_bufnr) - return selection.path -end - -local switch_worktree = function(prompt_bufnr) - local worktree_path = get_worktree_path(prompt_bufnr) - actions.close(prompt_bufnr) - if worktree_path ~= nil then - git_worktree.switch_worktree(worktree_path) - end -end - -local toggle_forced_deletion = function() - -- redraw otherwise the message is not displayed when in insert mode - if force_next_deletion then - print("The next deletion will not be forced") - vim.fn.execute("redraw") - else - print("The next deletion will be forced") - vim.fn.execute("redraw") - force_next_deletion = true - end -end - -local delete_success_handler = function() - force_next_deletion = false -end - -local delete_failure_handler = function() - print("Deletion failed, use to force the next deletion") -end - -local ask_to_confirm_deletion = function(forcing) - if forcing then - return vim.fn.input("Force deletion of worktree? [y/n]: ") - end - - return vim.fn.input("Delete worktree? [y/n]: ") -end - -local confirm_deletion = function(forcing) - if not git_worktree._config.confirm_telescope_deletions then - return true - end - - local confirmed = ask_to_confirm_deletion(forcing) - - if string.sub(string.lower(confirmed), 0, 1) == "y" then - return true - end - - print("Didn't delete worktree") - return false -end - -local delete_worktree = function(prompt_bufnr) - if not confirm_deletion() then - return - end - - local worktree_path = get_worktree_path(prompt_bufnr) - actions.close(prompt_bufnr) - if worktree_path ~= nil then - git_worktree.delete_worktree(worktree_path, force_next_deletion, { - on_failure = delete_failure_handler, - on_success = delete_success_handler, - }) - end -end - -local create_input_prompt = function(cb) - --[[ - local window = Window.centered({ - width = 30, - height = 1 - }) - vim.api.nvim_buf_set_option(window.bufnr, "buftype", "prompt") - vim.fn.prompt_setprompt(window.bufnr, "Worktree Location: ") - vim.fn.prompt_setcallback(window.bufnr, function(text) - vim.api.nvim_win_close(window.win_id, true) - vim.api.nvim_buf_delete(window.bufnr, {force = true}) - cb(text) - end) - - vim.api.nvim_set_current_win(window.win_id) - vim.fn.schedule(function() - vim.nvim_command("startinsert") - end) - --]] - -- - - local subtree = vim.fn.input("Path to subtree > ") - cb(subtree) -end - -local create_worktree = function(opts) - opts = opts or {} - opts.attach_mappings = function() - actions.select_default:replace(function(prompt_bufnr, _) - local selected_entry = action_state.get_selected_entry() - local current_line = action_state.get_current_line() - - actions.close(prompt_bufnr) - - local branch = selected_entry ~= nil and selected_entry.value or current_line - - if branch == nil then - return - end - - create_input_prompt(function(name) - if name == "" then - name = branch - end - git_worktree.create_worktree(name, branch) - end) - end) - - -- do we need to replace other default maps? - - return true - end - require("telescope.builtin").git_branches(opts) -end - -local telescope_git_worktree = function(opts) - opts = opts or {} - local output = utils.get_os_command_output({ "git", "worktree", "list" }) - local results = {} - local widths = { - path = 0, - sha = 0, - branch = 0, - } - - local parse_line = function(line) - local fields = vim.split(string.gsub(line, "%s+", " "), " ") - local entry = { - path = fields[1], - sha = fields[2], - branch = fields[3], - } - - if entry.sha ~= "(bare)" then - local index = #results + 1 - for key, val in pairs(widths) do - if key == "path" then - local new_path = utils.transform_path(opts, entry[key]) - local path_len = strings.strdisplaywidth(new_path or "") - widths[key] = math.max(val, path_len) - else - widths[key] = math.max(val, strings.strdisplaywidth(entry[key] or "")) - end - end - - table.insert(results, index, entry) - end - end - - for _, line in ipairs(output) do - parse_line(line) - end - - if #results == 0 then - return - end - - local displayer = require("telescope.pickers.entry_display").create({ - separator = " ", - items = { - { width = widths.branch }, - { width = widths.path }, - { width = widths.sha }, - }, - }) - - local make_display = function(entry) - return displayer({ - { entry.branch, "TelescopeResultsIdentifier" }, - { utils.transform_path(opts, entry.path) }, - { entry.sha }, - }) - end - - pickers - .new(opts or {}, { - prompt_title = "Git Worktrees", - finder = finders.new_table({ - results = results, - entry_maker = function(entry) - entry.value = entry.branch - entry.ordinal = entry.branch - entry.display = make_display - return entry - end, - }), - sorter = conf.generic_sorter(opts), - attach_mappings = function(_, map) - action_set.select:replace(switch_worktree) - - map("i", "", delete_worktree) - map("n", "", delete_worktree) - map("i", "", toggle_forced_deletion) - map("n", "", toggle_forced_deletion) - - return true - end, - }) - :find() -end - -return require("telescope").register_extension({ +-- local strings = require("plenary.strings") +-- local pickers = require("telescope.pickers") +-- local finders = require("telescope.finders") +-- local actions = require("telescope.actions") +-- local utils = require("telescope.utils") +-- local action_set = require("telescope.actions.set") +-- local action_state = require("telescope.actions.state") +-- local conf = require("telescope.config").values +-- local git_worktree = require("git-worktree") + +-- local force_next_deletion = false +-- +-- local get_worktree_path = function(prompt_bufnr) +-- local selection = action_state.get_selected_entry(prompt_bufnr) +-- return selection.path +-- end +-- +-- local switch_worktree = function(prompt_bufnr) +-- local worktree_path = get_worktree_path(prompt_bufnr) +-- actions.close(prompt_bufnr) +-- if worktree_path ~= nil then +-- git_worktree.switch_worktree(worktree_path) +-- end +-- end +-- +-- local toggle_forced_deletion = function() +-- -- redraw otherwise the message is not displayed when in insert mode +-- if force_next_deletion then +-- print("The next deletion will not be forced") +-- vim.fn.execute("redraw") +-- else +-- print("The next deletion will be forced") +-- vim.fn.execute("redraw") +-- force_next_deletion = true +-- end +-- end +-- +-- local delete_success_handler = function() +-- force_next_deletion = false +-- end +-- +-- local delete_failure_handler = function() +-- print("Deletion failed, use to force the next deletion") +-- end +-- +-- local ask_to_confirm_deletion = function(forcing) +-- if forcing then +-- return vim.fn.input("Force deletion of worktree? [y/n]: ") +-- end +-- +-- return vim.fn.input("Delete worktree? [y/n]: ") +-- end +-- +-- local confirm_deletion = function(forcing) +-- if not git_worktree._config.confirm_telescope_deletions then +-- return true +-- end +-- +-- local confirmed = ask_to_confirm_deletion(forcing) +-- +-- if string.sub(string.lower(confirmed), 0, 1) == "y" then +-- return true +-- end +-- +-- print("Didn't delete worktree") +-- return false +-- end +-- +-- local delete_worktree = function(prompt_bufnr) +-- if not confirm_deletion() then +-- return +-- end +-- +-- local worktree_path = get_worktree_path(prompt_bufnr) +-- actions.close(prompt_bufnr) +-- if worktree_path ~= nil then +-- git_worktree.delete_worktree(worktree_path, force_next_deletion, { +-- on_failure = delete_failure_handler, +-- on_success = delete_success_handler, +-- }) +-- end +-- end +-- +-- local create_input_prompt = function(cb) +-- --[[ +-- local window = Window.centered({ +-- width = 30, +-- height = 1 +-- }) +-- vim.api.nvim_buf_set_option(window.bufnr, "buftype", "prompt") +-- vim.fn.prompt_setprompt(window.bufnr, "Worktree Location: ") +-- vim.fn.prompt_setcallback(window.bufnr, function(text) +-- vim.api.nvim_win_close(window.win_id, true) +-- vim.api.nvim_buf_delete(window.bufnr, {force = true}) +-- cb(text) +-- end) +-- +-- vim.api.nvim_set_current_win(window.win_id) +-- vim.fn.schedule(function() +-- vim.nvim_command("startinsert") +-- end) +-- --]] +-- -- +-- +-- local subtree = vim.fn.input("Path to subtree > ") +-- cb(subtree) +-- end +-- +-- local create_worktree = function(opts) +-- opts = opts or {} +-- opts.attach_mappings = function() +-- actions.select_default:replace(function(prompt_bufnr, _) +-- local selected_entry = action_state.get_selected_entry() +-- local current_line = action_state.get_current_line() +-- +-- actions.close(prompt_bufnr) +-- +-- local branch = selected_entry ~= nil and selected_entry.value or current_line +-- +-- if branch == nil then +-- return +-- end +-- +-- create_input_prompt(function(name) +-- if name == "" then +-- name = branch +-- end +-- git_worktree.create_worktree(name, branch) +-- end) +-- end) +-- +-- -- do we need to replace other default maps? +-- +-- return true +-- end +-- require("telescope.builtin").git_branches(opts) +-- end +-- +-- local telescope_git_worktree = function(opts) +-- opts = opts or {} +-- local output = utils.get_os_command_output({ "git", "worktree", "list" }) +-- local results = {} +-- local widths = { +-- path = 0, +-- sha = 0, +-- branch = 0, +-- } +-- +-- local parse_line = function(line) +-- local fields = vim.split(string.gsub(line, "%s+", " "), " ") +-- local entry = { +-- path = fields[1], +-- sha = fields[2], +-- branch = fields[3], +-- } +-- +-- if entry.sha ~= "(bare)" then +-- local index = #results + 1 +-- for key, val in pairs(widths) do +-- if key == "path" then +-- local new_path = utils.transform_path(opts, entry[key]) +-- local path_len = strings.strdisplaywidth(new_path or "") +-- widths[key] = math.max(val, path_len) +-- else +-- widths[key] = math.max(val, strings.strdisplaywidth(entry[key] or "")) +-- end +-- end +-- +-- table.insert(results, index, entry) +-- end +-- end +-- +-- for _, line in ipairs(output) do +-- parse_line(line) +-- end +-- +-- if #results == 0 then +-- return +-- end +-- +-- local displayer = require("telescope.pickers.entry_display").create({ +-- separator = " ", +-- items = { +-- { width = widths.branch }, +-- { width = widths.path }, +-- { width = widths.sha }, +-- }, +-- }) +-- +-- local make_display = function(entry) +-- return displayer({ +-- { entry.branch, "TelescopeResultsIdentifier" }, +-- { utils.transform_path(opts, entry.path) }, +-- { entry.sha }, +-- }) +-- end +-- +-- pickers +-- .new(opts or {}, { +-- prompt_title = "Git Worktrees", +-- finder = finders.new_table({ +-- results = results, +-- entry_maker = function(entry) +-- entry.value = entry.branch +-- entry.ordinal = entry.branch +-- entry.display = make_display +-- return entry +-- end, +-- }), +-- sorter = conf.generic_sorter(opts), +-- attach_mappings = function(_, map) +-- action_set.select:replace(switch_worktree) +-- +-- map("i", "", delete_worktree) +-- map("n", "", delete_worktree) +-- map("i", "", toggle_forced_deletion) +-- map("n", "", toggle_forced_deletion) +-- +-- return true +-- end, +-- }) +-- :find() +-- end +-- +return require('telescope').register_extension { exports = { - git_worktree = telescope_git_worktree, - create_git_worktree = create_worktree, + -- git_worktree = telescope_git_worktree, + -- create_git_worktree = create_worktree, }, -}) +} diff --git a/spec/git_spec.lua b/spec/git_spec.lua index 043452c..f3ae6b9 100644 --- a/spec/git_spec.lua +++ b/spec/git_spec.lua @@ -1,39 +1,42 @@ -local git_harness = require("util.git_harness") -local gwt_git = require("git-worktree.git") -local Status = require("git-worktree.status") +local git_harness = require('util.git_harness') +local gwt_git = require('git-worktree.git') +local Status = require('git-worktree.status') local status = Status:new() -- luacheck: globals repo_dir -describe("git-worktree git operations", function() - describe("finds git toplevel in normal repo", function() +describe('git-worktree git operations', function() + describe('finds git toplevel in normal repo', function() before_each(function() repo_dir = git_harness.prepare_repo() + status:reset(0) end) - it("Public API is available after setup.", function() + it('Public API is available after setup.', function() local ret_git_dir = gwt_git.find_git_dir() assert.are.same(ret_git_dir, repo_dir) end) end) - describe("finds git toplevel in bare repo", function() + describe('finds git toplevel in bare repo', function() before_each(function() repo_dir = git_harness.prepare_repo_bare() + status:reset(0) end) - it("no toplevel in a bare repo", function() + it('no toplevel in a bare repo', function() local ret_git_dir = gwt_git.find_git_dir() assert.are.same(ret_git_dir, nil) end) end) - describe("finds git toplevel in worktree repo", function() + describe('finds git toplevel in worktree repo', function() before_each(function() repo_dir = git_harness.prepare_repo_worktree() + status:reset(0) end) - it("Public API is available after setup.", function() + it('Public API is available after setup.', function() local ret_git_dir = gwt_git.find_git_dir() - status:log().info("ret_git_dir: " .. ret_git_dir .. ".") - status:log().info("repo_dir : " .. repo_dir .. ".") + status:status('ret_git_dir: ' .. ret_git_dir .. '.') + status:status('repo_dir : ' .. repo_dir .. '.') assert.are.same(ret_git_dir, repo_dir) end) end) diff --git a/spec/setup_spec.lua b/spec/setup_spec.lua index d6b6ba4..34d7867 100644 --- a/spec/setup_spec.lua +++ b/spec/setup_spec.lua @@ -1,5 +1,5 @@ -describe("Can require haskell-tools with default configs.", function() - it("Public API is available after setup.", function() +describe('Can require haskell-tools with default configs.', function() + it('Public API is available after setup.', function() assert(1 == 1) end) end) diff --git a/spec/util/git_harness.lua b/spec/util/git_harness.lua index 0d577fa..d797214 100644 --- a/spec/util/git_harness.lua +++ b/spec/util/git_harness.lua @@ -1,4 +1,4 @@ -local system = require("util.system") +local system = require('util.system') local M = {} @@ -9,9 +9,9 @@ function M.setup_origin_repo() return origin_repo_path end - local workspace_dir = system.create_temp_dir("workspace-dir") + local workspace_dir = system.create_temp_dir('workspace-dir') vim.api.nvim_set_current_dir(vim.fn.getcwd()) - system.run("cp -r spec/.repo " .. workspace_dir) + system.run('cp -r spec/.repo ' .. workspace_dir) vim.api.nvim_set_current_dir(workspace_dir) system.run([[ mv .repo/.git-orig ./.git @@ -20,8 +20,8 @@ function M.setup_origin_repo() git config user.name "Test User" ]]) - origin_repo_path = system.create_temp_dir("origin-repo") - system.run(string.format("git clone --bare %s %s", workspace_dir, origin_repo_path)) + origin_repo_path = system.create_temp_dir('origin-repo') + system.run(string.format('git clone --bare %s %s', workspace_dir, origin_repo_path)) return origin_repo_path end @@ -29,9 +29,9 @@ end function M.prepare_repo() M.setup_origin_repo() - local working_dir = system.create_temp_dir("working-dir") + local working_dir = system.create_temp_dir('working-dir') vim.api.nvim_set_current_dir(working_dir) - system.run(string.format("git clone %s %s", origin_repo_path, working_dir)) + system.run(string.format('git clone %s %s', origin_repo_path, working_dir)) system.run([[ git config remote.origin.url git@github.com:test/test.git git config user.email "test@test.test" @@ -43,20 +43,20 @@ end function M.prepare_repo_bare() M.setup_origin_repo() - local working_dir = system.create_temp_dir("working-bare-dir") + local working_dir = system.create_temp_dir('working-bare-dir') vim.api.nvim_set_current_dir(working_dir) - system.run(string.format("git clone --bare %s %s", origin_repo_path, working_dir)) + system.run(string.format('git clone --bare %s %s', origin_repo_path, working_dir)) return working_dir end function M.prepare_repo_worktree() M.setup_origin_repo() - local working_dir = system.create_temp_dir("working-worktree-dir") + local working_dir = system.create_temp_dir('working-worktree-dir') vim.api.nvim_set_current_dir(working_dir) - system.run(string.format("git clone --bare %s %s", origin_repo_path, working_dir)) - system.run("git worktree add wt master") - local worktree_dir = working_dir .. "/wt" + system.run(string.format('git clone --bare %s %s', origin_repo_path, working_dir)) + system.run('git worktree add wt master') + local worktree_dir = working_dir .. '/wt' vim.api.nvim_set_current_dir(worktree_dir) return worktree_dir end diff --git a/spec/util/system.lua b/spec/util/system.lua index 67f0408..2a1e51a 100644 --- a/spec/util/system.lua +++ b/spec/util/system.lua @@ -12,29 +12,29 @@ function M.run(cmd, ignore_err, error_msg) local output = vim.fn.system(cmd) if vim.v.shell_error ~= 0 and not ignore_err then - error(error_msg or ("Command failed: ↓\n" .. cmd .. "\nOutput from command: ↓\n" .. output)) + error(error_msg or ('Command failed: ↓\n' .. cmd .. '\nOutput from command: ↓\n' .. output)) end return output end local function is_macos() - return vim.loop.os_uname().sysname == "Darwin" + return vim.loop.os_uname().sysname == 'Darwin' end ---Create a temporary directory for use ---@param suffix string? The suffix to be appended to the temp directory, ideally avoid spaces in your suffix ---@return string The path to the temporary directory function M.create_temp_dir(suffix) - suffix = "git-worktree-" .. (suffix or "") + suffix = 'git-worktree-' .. (suffix or '') local cmd if is_macos() then - cmd = string.format("mktemp -d -t %s", suffix) + cmd = string.format('mktemp -d -t %s', suffix) else - cmd = string.format("mktemp -d --suffix=%s", suffix) + cmd = string.format('mktemp -d --suffix=%s', suffix) end - local prefix = is_macos() and "/private" or "" + local prefix = is_macos() and '/private' or '' return prefix .. vim.trim(M.run(cmd)) end diff --git a/tests/git_harness.lua b/tests/git_harness.lua deleted file mode 100644 index 2c2682c..0000000 --- a/tests/git_harness.lua +++ /dev/null @@ -1,405 +0,0 @@ -local git_worktree = require("git-worktree") -local Job = require("plenary.job") -local Path = require("plenary.path") - -local M = {} - -local get_os_command_output = function(cmd) - local command = table.remove(cmd, 1) - local stderr = {} - local stdout, ret = Job:new({ - command = command, - args = cmd, - cwd = git_worktree.get_root(), - on_stderr = function(_, data) - table.insert(stderr, data) - end, - }):sync() - return stdout, ret, stderr -end - -local prepare_origin_repo = function(dir) - vim.api.nvim_exec("!cp -r tests/repo_origin/ /tmp/" .. dir, true) - vim.api.nvim_exec("!mv /tmp/" .. dir .. "/.git-orig /tmp/" .. dir .. "/.git", true) -end - -local prepare_bare_repo = function(dir, origin_dir) - vim.api.nvim_exec("!git clone --bare /tmp/" .. origin_dir .. " /tmp/" .. dir, true) -end - -local fix_fetch_all = function() - vim.api.nvim_exec('!git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"', true) -end - -local prepare_repo = function(dir, origin_dir) - vim.api.nvim_exec("!git clone /tmp/" .. origin_dir .. " /tmp/" .. dir, true) -end - -local random_string = function() - math.randomseed(os.clock() ^ 5) - local ret = "" - for _ = 1, 5 do - local random_char = math.random(97, 122) - ret = ret .. string.char(random_char) - end - return ret -end - -local change_dir = function(dir) - vim.api.nvim_set_current_dir("/tmp/" .. dir) - git_worktree.set_worktree_root("/tmp/" .. dir) -end - -local cleanup_repos = function() - vim.api.nvim_exec("silent !rm -rf /tmp/git_worktree_test*", true) -end - -local create_worktree = function(folder_path, commitish) - vim.api.nvim_exec("!git worktree add " .. folder_path .. " " .. commitish, true) -end - -local project_dir = vim.api.nvim_exec("pwd", true) - -local reset_cwd = function() - vim.cmd("cd " .. project_dir) - vim.api.nvim_set_current_dir(project_dir) -end - -local config_git_worktree = function() - git_worktree.setup({}) -end - -M.in_non_git_repo = function(cb) - return function() - local random_id = random_string() - local dir = "git_worktree_test_repo_" .. random_id - - config_git_worktree() - cleanup_repos() - - Path:new("/tmp/" .. dir):mkdir() - change_dir(dir) - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_bare_repo_from_origin_no_worktrees = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local bare_repo_dir = "git_worktree_test_repo_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_bare_repo(bare_repo_dir, origin_repo_dir) - - change_dir(bare_repo_dir) - fix_fetch_all() - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_repo_from_origin_no_worktrees = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local repo_dir = "git_worktree_test_repo_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_repo(repo_dir, origin_repo_dir) - - change_dir(repo_dir) - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_repo_from_local_no_worktrees = function(cb) - return function() - local random_id = random_string() - local local_repo_dir = "git_worktree_test_origin_repo_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(local_repo_dir) - - change_dir(local_repo_dir) - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_bare_repo_from_origin_1_worktree = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local bare_repo_dir = "git_worktree_test_repo_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_bare_repo(bare_repo_dir, origin_repo_dir) - change_dir(bare_repo_dir) - create_worktree("master", "master") - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_repo_from_origin_1_worktree = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local repo_dir = "git_worktree_test_repo_" .. random_id - local feat_dir = "git_worktree_test_repo_featB_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_repo(repo_dir, origin_repo_dir) - change_dir(repo_dir) - - create_worktree("../" .. feat_dir, "featB") - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_bare_repo_from_origin_2_worktrees = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local bare_repo_dir = "git_worktree_test_repo_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_bare_repo(bare_repo_dir, origin_repo_dir) - change_dir(bare_repo_dir) - create_worktree("featB", "featB") - create_worktree("featC", "featC") - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_repo_from_origin_2_worktrees = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local repo_dir = "git_worktree_test_repo_" .. random_id - local featB_dir = "git_worktree_test_repo_featB_" .. random_id - local featC_dir = "git_worktree_test_repo_featC_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_repo(repo_dir, origin_repo_dir) - change_dir(repo_dir) - - create_worktree("../" .. featB_dir, "featB") - create_worktree("../" .. featC_dir, "featC") - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_bare_repo_from_origin_2_similar_named_worktrees = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local bare_repo_dir = "git_worktree_test_repo_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_bare_repo(bare_repo_dir, origin_repo_dir) - change_dir(bare_repo_dir) - create_worktree("featB", "featB") - create_worktree("featB-test", "featC") - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -M.in_repo_from_origin_2_similar_named_worktrees = function(cb) - return function() - local random_id = random_string() - local origin_repo_dir = "git_worktree_test_origin_repo_" .. random_id - local repo_dir = "git_worktree_test_repo_" .. random_id - local featB_dir = "git_worktree_test_repo_featB_" .. random_id - local featC_dir = "git_worktree_test_repo_featB-test_" .. random_id - - config_git_worktree() - cleanup_repos() - - prepare_origin_repo(origin_repo_dir) - prepare_repo(repo_dir, origin_repo_dir) - change_dir(repo_dir) - - create_worktree("../" .. featB_dir, "featB") - create_worktree("../" .. featC_dir, "featC") - - local _, err = pcall(cb) - - reset_cwd() - - cleanup_repos() - - if err ~= nil then - error(err) - end - end -end - -local get_git_branches_upstreams = function() - local output = get_os_command_output({ - "git", - "for-each-ref", - "--format", - "'%(refname:short),%(upstream:short)'", - "refs/heads", - }) - return output -end - -M.check_branch_upstream = function(branch, upstream) - local correct_branch = false - local correct_upstream = false - local upstream_to_check - - if upstream == nil then - upstream_to_check = "" - else - upstream_to_check = upstream .. "/" .. branch - end - - local refs = get_git_branches_upstreams() - for _, ref in ipairs(refs) do - ref = ref:gsub("'", "") - local line = vim.split(ref, ",", true) - local b = line[1] - local u = line[2] - - if b == branch then - correct_branch = true - correct_upstream = (u == upstream_to_check) - end - end - - return correct_branch, correct_upstream -end - -local get_git_worktrees = function() - local output = get_os_command_output({ - "git", - "worktree", - "list", - }) - return output -end - -M.check_git_worktree_exists = function(worktree_path) - local worktree_exists = false - - local refs = get_git_worktrees() - for _, line in ipairs(refs) do - local worktree_line = {} - for section in line:gmatch("%S+") do - table.insert(worktree_line, section) - end - - if worktree_path == worktree_line[1] then - worktree_exists = true - end - end - - return worktree_exists -end - -return M diff --git a/tests/minimal_init.vim b/tests/minimal_init.vim deleted file mode 100644 index da29e2f..0000000 --- a/tests/minimal_init.vim +++ /dev/null @@ -1,4 +0,0 @@ -set rtp+=. -set rtp+=../plenary.nvim/ - -runtime! plugin/plenary.vim diff --git a/tests/worktree_spec.lua b/tests/worktree_spec.lua deleted file mode 100644 index d3b96b8..0000000 --- a/tests/worktree_spec.lua +++ /dev/null @@ -1,772 +0,0 @@ -local git_worktree = require("git-worktree") -local Path = require("plenary.path") - -local harness = require("tests.git_harness") -local in_non_git_repo = harness.in_non_git_repo -local in_bare_repo_from_origin_no_worktrees = harness.in_bare_repo_from_origin_no_worktrees -local in_repo_from_origin_no_worktrees = harness.in_repo_from_origin_no_worktrees -local in_bare_repo_from_origin_1_worktree = harness.in_bare_repo_from_origin_1_worktree -local in_repo_from_origin_1_worktree = harness.in_repo_from_origin_1_worktree -local in_repo_from_local_no_worktrees = harness.in_repo_from_local_no_worktrees -local in_bare_repo_from_origin_2_worktrees = harness.in_bare_repo_from_origin_2_worktrees -local in_repo_from_origin_2_worktrees = harness.in_repo_from_origin_2_worktrees -local in_bare_repo_from_origin_2_similar_named_worktrees = harness.in_bare_repo_from_origin_2_similar_named_worktrees ---local in_repo_from_origin_2_similar_named_worktrees = harness.in_repo_from_origin_2_similar_named_worktrees -local check_git_worktree_exists = harness.check_git_worktree_exists -local check_branch_upstream = harness.check_branch_upstream - -describe("git-worktree", function() - local completed_create = false - local completed_switch = false - local completed_delete = false - - local reset_variables = function() - completed_create = false - completed_switch = false - completed_delete = false - end - - before_each(function() - reset_variables() - git_worktree.on_tree_change(function(op, _, _) - if op == git_worktree.Operations.Create then - completed_create = true - end - if op == git_worktree.Operations.Switch then - completed_switch = true - end - if op == git_worktree.Operations.Delete then - completed_delete = true - end - end) - end) - - after_each(function() - git_worktree.reset() - end) - - describe("Create", function() - it( - "can create a worktree(from origin)(relative path) from a bare repo and switch to it", - in_bare_repo_from_origin_no_worktrees(function() - local branch = "master" - local upstream = "origin" - local path = "master" - git_worktree.create_worktree(path, branch, upstream) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - local expected_path = git_worktree:get_root() .. Path.path.sep .. path - -- Check to make sure directory was switched - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(from origin)(absolute path) from a bare repo and switch to it", - in_bare_repo_from_origin_no_worktrees(function() - local branch = "master" - local upstream = "origin" - local path = git_worktree.get_root() .. Path.path.sep .. "master" - git_worktree.create_worktree(path, branch, upstream) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(from origin)(relative path) from a repo and switch to it", - in_repo_from_origin_no_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local branch = "featB" - local upstream = "origin" - local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str - git_worktree.create_worktree(path, branch, upstream) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(from origin)(absolute path) from a repo and switch to it", - in_repo_from_origin_no_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local branch = "featB" - local upstream = "origin" - local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - - git_worktree.create_worktree(path, branch, upstream) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(no upstream but detect origin)(relative path) from a bare repo and switch to it", - in_bare_repo_from_origin_no_worktrees(function() - local branch = "master" - local upstream = "origin" - local path = "master" - git_worktree.create_worktree(path, branch) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - local expected_path = git_worktree:get_root() .. "/" .. path - - -- Check to make sure directory was switched - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(no upstream but detect origin)(absolute path) from a bare repo and switch to it", - in_bare_repo_from_origin_no_worktrees(function() - local branch = "master" - local upstream = "origin" - local path = git_worktree:get_root() .. Path.path.sep .. "master" - - git_worktree.create_worktree(path, branch) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(no upstream but detect origin)(relative path) from a repo and switch to it", - in_repo_from_origin_no_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local branch = "featB" - local upstream = "origin" - local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str - git_worktree.create_worktree(path, branch) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(no upstream but detect origin)(absolute path) from a repo and switch to it", - in_repo_from_origin_no_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local branch = "featB" - local upstream = "origin" - local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - - git_worktree.create_worktree(path, branch) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(no upstream no origin)(relative path) from a repo and switch to it", - in_repo_from_local_no_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local branch = "featB" - local upstream = nil - local path = "../git_worktree_test_repo_" .. branch .. "_" .. random_str - git_worktree.create_worktree(path, branch) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() - assert.are.same(expected_path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(expected_path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - - it( - "can create a worktree(no upstream no origin)(absolute path) from a repo and switch to it", - in_repo_from_local_no_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local branch = "featB" - local upstream = nil - local path = "/tmp/git_worktree_test_repo_" .. branch .. "_" .. random_str - - git_worktree.create_worktree(path, branch) - - vim.fn.wait(10000, function() - return completed_create and completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(path, vim.loop.cwd()) - - -- Check to make sure it is added to git worktree list - assert.True(check_git_worktree_exists(path)) - - -- check to make sure branch/upstream is correct - local correct_branch, correct_upstream = check_branch_upstream(branch, upstream) - assert.True(correct_branch) - assert.True(correct_upstream) - end) - ) - end) - - describe("Switch", function() - it( - "from a bare repo with one worktree, able to switch to worktree (relative path)", - in_bare_repo_from_origin_1_worktree(function() - local path = "master" - git_worktree.switch_worktree(path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) - end) - ) - - it( - "from a bare repo with one worktree, able to switch to worktree (absolute path)", - in_bare_repo_from_origin_1_worktree(function() - local path = git_worktree:get_root() .. Path.path.sep .. "master" - git_worktree.switch_worktree(path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) - end) - ) - - it( - "from a repo with one worktree, able to switch to worktree (relative path)", - in_repo_from_origin_1_worktree(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local path = "../git_worktree_test_repo_featB_" .. random_str - git_worktree.switch_worktree(path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - local expected_path = Path:new(git_worktree:get_root() .. "/" .. path):normalize() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), expected_path) - end) - ) - - it( - "from a repo with one worktree, able to switch to worktree (absolute path)", - in_repo_from_origin_1_worktree(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local path = "/tmp/git_worktree_test_repo_featB_" .. random_str - git_worktree.switch_worktree(path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) - end) - ) - - local get_current_file = function() - return vim.api.nvim_buf_get_name(0) - end - - it( - "in a featB worktree(bare) with file A open, switch to featC and switch to file A in other worktree", - in_bare_repo_from_origin_2_worktrees(function() - local featB_path = "featB" - local featB_abs_path = git_worktree:get_root() .. Path.path.sep .. featB_path - local featB_abs_A_path = featB_abs_path .. Path.path.sep .. "A.txt" - - local featC_path = "featC" - local featC_abs_path = git_worktree:get_root() .. Path.path.sep .. featC_path - local featC_abs_A_path = featC_abs_path .. Path.path.sep .. "A.txt" - - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- open A file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(featB_abs_A_path == get_current_file()) - - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- make sure it switch to file in other tree - assert.True(featC_abs_A_path == get_current_file()) - end) - ) - - it( - "in a featB worktree(non bare) with file A open, switch to featC and switch to file A in other worktree", - in_repo_from_origin_2_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - - local featB_path = "../git_worktree_test_repo_featB_" .. random_str - local featB_abs_path = "/tmp/git_worktree_test_repo_featB_" .. random_str - local featB_abs_A_path = featB_abs_path .. "/A.txt" - - local featC_path = "../git_worktree_test_repo_featC_" .. random_str - local featC_abs_path = "/tmp/git_worktree_test_repo_featC_" .. random_str - local featC_abs_A_path = featC_abs_path .. "/A.txt" - - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- open A file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(featB_abs_A_path == get_current_file()) - - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- make sure it switch to file in other tree - assert.True(featC_abs_A_path == get_current_file()) - end) - ) - - it( - "in a featB worktree(bare) with file B open, switch to featC and switch to worktree root in other worktree", - in_bare_repo_from_origin_2_worktrees(function() - local featB_path = "featB" - local featB_abs_path = git_worktree:get_root() .. Path.path.sep .. featB_path - local featB_abs_B_path = featB_abs_path .. Path.path.sep .. "B.txt" - - local featC_path = "featC" - local featC_abs_path = git_worktree:get_root() .. Path.path.sep .. featC_path - - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- open B file - vim.cmd("e B.txt") - -- make sure it is opensd - assert.True(featB_abs_B_path == get_current_file()) - - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- make sure it switch to file in other tree - assert.True(featC_abs_path == get_current_file()) - end) - ) - - it( - "in a featB worktree(non bare) with file B open, switch to featC and switch to worktree" - .. " root in other worktree", - in_repo_from_origin_2_worktrees(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - - local featB_path = "../git_worktree_test_repo_featB_" .. random_str - local featB_abs_path = "/tmp/git_worktree_test_repo_featB_" .. random_str - local featB_abs_B_path = featB_abs_path .. "/B.txt" - - local featC_path = "../git_worktree_test_repo_featC_" .. random_str - local featC_abs_path = "/tmp/git_worktree_test_repo_featC_" .. random_str - - -- switch to featB worktree - git_worktree.switch_worktree(featB_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- open A file - vim.cmd("e B.txt") - -- make sure it is opensd - assert.True(featB_abs_B_path == get_current_file()) - - -- switch to featB worktree - reset_variables() - git_worktree.switch_worktree(featC_path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- make sure it switch to file in other tree - assert.True(featC_abs_path == get_current_file()) - end) - ) - - it( - "from a bare repo with two worktrees, able to switch to worktree with similar names (relative path)", - in_bare_repo_from_origin_2_similar_named_worktrees(function() - local path1 = "featB" - local path2 = "featB-test" - git_worktree.switch_worktree(path1) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path1) - - -- open A file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(vim.loop.cwd() .. "/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path2) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path2) - -- Make sure file is switched - assert.True(vim.loop.cwd() .. "/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path1) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path1) - -- Make sure file is switched - assert.True(vim.loop.cwd() .. "/A.txt" == get_current_file()) - end) - ) - - it( - "from a bare repo with two worktrees, able to switch to worktree with similar names (absolute path)", - in_bare_repo_from_origin_2_similar_named_worktrees(function() - local path1 = git_worktree:get_root() .. Path.path.sep .. "featB" - local path2 = git_worktree:get_root() .. Path.path.sep .. "featB-test" - - git_worktree.switch_worktree(path1) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path1) - - -- open B file - vim.cmd("e A.txt") - -- make sure it is opensd - assert.True(path1 .. "/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path2) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - reset_variables() - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path2) - -- Make sure file is switched - assert.True(path2 .. "/A.txt" == get_current_file()) - - git_worktree.switch_worktree(path1) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path1) - -- Make sure file is switched - assert.True(path1 .. "/A.txt" == get_current_file()) - end) - ) - end) - - describe("Delete", function() - it( - "from a bare repo with one worktree, able to delete the worktree (relative path)", - in_bare_repo_from_origin_1_worktree(function() - local path = "master" - git_worktree.delete_worktree(path) - - vim.fn.wait(10000, function() - return completed_delete - end, 1000) - - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(git_worktree:get_root() .. Path.path.sep .. path)) - - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - end) - ) - - it( - "from a bare repo with one worktree, able to delete the worktree (absolute path)", - in_bare_repo_from_origin_1_worktree(function() - local path = git_worktree:get_root() .. Path.path.sep .. "master" - git_worktree.delete_worktree(path) - - vim.fn.wait(10000, function() - return completed_delete - end, 1000) - - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(path)) - - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - end) - ) - - it( - "from a repo with one worktree, able to delete the worktree (relative path)", - in_repo_from_origin_1_worktree(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local path = "../git_worktree_test_repo_featB_" .. random_str - local absolute_path = "/tmp/git_worktree_test_repo_featB_" .. random_str - git_worktree.delete_worktree(path, true) - - vim.fn.wait(10000, function() - return completed_delete - end, 1000) - - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(absolute_path)) - - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - end) - ) - - it( - "from a repo with one worktree, able to delete the worktree (absolute path)", - in_repo_from_origin_1_worktree(function() - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local path = "/tmp/git_worktree_test_repo_featB_" .. random_str - git_worktree.delete_worktree(path, true) - - vim.fn.wait(10000, function() - return completed_delete - end, 1000) - - -- Check to make sure it is added to git worktree list - assert.False(check_git_worktree_exists(path)) - - -- Check to make sure directory was not switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - end) - ) - end) - - describe("Find Git Root Dir / Current Worktree on load", function() - it( - "does not find the paths in a non git repo", - in_non_git_repo(function() - git_worktree:setup_git_info() - assert.are.same(nil, git_worktree:get_root()) - assert.are.same(nil, git_worktree:get_current_worktree_path()) - end) - ) - - it( - "finds the paths in a git repo", - in_repo_from_origin_1_worktree(function() - git_worktree:setup_git_info() - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) - end) - ) - - it( - "finds the paths in a bare git repo", - in_bare_repo_from_origin_1_worktree(function() - git_worktree:setup_git_info() - assert.are.same(vim.loop.cwd(), git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) - end) - ) - - it( - "finds the paths from a git repo in a worktree", - in_repo_from_origin_1_worktree(function() - local expected_git_repo = git_worktree:get_root() - -- switch to a worktree - local random_str = git_worktree.get_root():sub(git_worktree.get_root():len() - 4) - local path = "/tmp/git_worktree_test_repo_featB_" .. random_str - git_worktree.switch_worktree(path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), path) - - git_worktree:setup_git_info() - assert.are.same(expected_git_repo, git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) - end) - ) - - it( - "finds the paths from a bare git repo in a worktree", - in_bare_repo_from_origin_1_worktree(function() - local expected_git_repo = git_worktree:get_root() - -- switch to a worktree - local path = "master" - git_worktree.switch_worktree(path) - - vim.fn.wait(10000, function() - return completed_switch - end, 1000) - - -- Check to make sure directory was switched - assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) - - git_worktree:setup_git_info() - assert.are.same(expected_git_repo, git_worktree:get_root()) - assert.are.same(vim.loop.cwd(), git_worktree:get_current_worktree_path()) - end) - ) - end) -end) From b8724f33e5ead71edcfe938b79e889ed22eed632 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Sat, 11 Nov 2023 00:05:28 -0500 Subject: [PATCH 08/33] refactor: config --- lua/git-worktree/config.lua | 43 +++++++++++++------------------------ lua/git-worktree/init.lua | 22 +++++-------------- spec/config_spec.lua | 22 +++++++++++++++++++ 3 files changed, 42 insertions(+), 45 deletions(-) create mode 100644 spec/config_spec.lua diff --git a/lua/git-worktree/config.lua b/lua/git-worktree/config.lua index c2ecbb7..90cfd58 100644 --- a/lua/git-worktree/config.lua +++ b/lua/git-worktree/config.lua @@ -1,36 +1,23 @@ local M = {} ----@class GitWorktreeConfig +---@class GitWorktree.Config +local defaults = { + change_directory_command = 'cd', + update_on_change = true, + update_on_change_command = 'e .', + clearjumps_on_change = true, + confirm_telescope_deletions = true, + autopush = false, +} ----@class GitWorktreePartialConfig ----@field change_directory_command? string ----@field update_on_change? boolean ----@field update_on_change_command? string ----@field clearjumps_on_change? boolean ----@field confirm_telescope_deletions? boolean ----@field autopush? boolean +---@type GitWorktree.Config +M.options = {} ----@return GitWorktreeConfig -function M.get_default_config() - return { - change_directory_command = 'cd', - update_on_change = true, - update_on_change_command = 'e .', - clearjumps_on_change = true, - confirm_telescope_deletions = true, - autopush = false, - } +---@param opts? GitWorktree.Config +function M.setup(opts) + M.options = vim.tbl_deep_extend('force', defaults, opts or {}) end ----@param partial_config GitWorktreePartialConfig ----@param latest_config GitWorktreeConfig? ----@return GitWorktreeConfig -function M.merge_config(partial_config, latest_config) - local config = latest_config or M.get_default_config() - - config = vim.tbl_extend('force', config, partial_config) - - return config -end +M.setup() return M diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index b3964b2..5155367 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -2,7 +2,7 @@ -- local Path = require("plenary.path") -- local Enum = require("git-worktree.enum") -local Config = require('git-worktree.config') +-- local Config = require('git-worktree.config') -- local Git = require("git-worktree.git") -- local Hooks = require("git-worktree.hooks") local Status = require('git-worktree.status') @@ -17,21 +17,9 @@ local status = Status:new() local M = {} -M.__index = M - ----@return GitWorktree -function M:new() - local config = Config.get_default_config() - return setmetatable({ - config = config, - }, self) -end - ----@param partial_config GitWorktreePartialConfig ----@return GitWorktree -function M:setup(partial_config) - self.config = Config.merge_config(partial_config, self.config) - return self +---@param opts? GitWorktree.Config +function M.setup(opts) + require('git-worktree.config').setup(opts) end -- local function change_dirs(path) @@ -405,4 +393,4 @@ end -- M.setup() -- --M.Operations = Enum.Operations -return M:new() +return M diff --git a/spec/config_spec.lua b/spec/config_spec.lua new file mode 100644 index 0000000..7eae061 --- /dev/null +++ b/spec/config_spec.lua @@ -0,0 +1,22 @@ +local stub = require('luassert.stub') + +describe('config', function() + local notify_once = stub(vim, 'notify_once') + local notify = stub(vim, 'notify') + + it('returns the default config', function() + local Config = require('git-worktree.config') + assert.truthy(Config.options.change_directory_command) + end) + + it('can have configuration applied', function() + local Config = require('git-worktree.config') + Config.setup { change_directory_command = 'test' } + assert.equals(Config.options.change_directory_command, 'test') + end) + + it('No notifications at startup.', function() + assert.stub(notify_once).was_not_called() + assert.stub(notify).was_not_called() + end) +end) From fdd0a099f31901a4dfa6c8fcb4661fc67fff921d Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 27 Dec 2023 23:05:26 -0500 Subject: [PATCH 09/33] ci: add commit-lint workflow --- .github/workflows/commit_lint.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/commit_lint.yml diff --git a/.github/workflows/commit_lint.yml b/.github/workflows/commit_lint.yml new file mode 100644 index 0000000..e1df4ca --- /dev/null +++ b/.github/workflows/commit_lint.yml @@ -0,0 +1,12 @@ +on: [pull_request] +jobs: + lint-commits: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: npm install --save-dev @commitlint/{cli,config-conventional} + - run: | + echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js + - run: npx commitlint --from HEAD~1 --to HEAD --verbose From 3ebddeb6c854bc2726862e0141f0f80837c0f43d Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 27 Dec 2023 23:05:45 -0500 Subject: [PATCH 10/33] ci: switch to vusted for testing --- .github/workflows/ci.yml | 75 ++++------ .gitignore | 4 - flake.lock | 307 ++++----------------------------------- flake.nix | 33 +---- 4 files changed, 57 insertions(+), 362 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40fc3d1..076c33c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,57 +1,38 @@ -name: Tests +name: test -on: [push, pull_request] +on: + pull_request: jobs: - x64-ubuntu: - name: X64-ubuntu - runs-on: ubuntu-20.04 + test: + name: Run Test + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v2 - - run: date +%F > todays-date - - name: Restore cache for today's nightly. - uses: actions/cache@v2 + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + id: vim with: - path: | - _neovim - key: ${{ runner.os }}-x64-${{ hashFiles('todays-date') }} + neovim: true + version: nightly - - name: Prepare - run: | - mkdir -p ~/.local/share/nvim/site/pack/vendor/start - git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim - ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start - - name: Run tests - run: | - curl -OL https://raw.githubusercontent.com/norcalli/bot-ci/master/scripts/github-actions-setup.sh - source github-actions-setup.sh nightly-x64 - make test - - appimage-ubuntu: - name: Appimage-ubuntu - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - run: date +%F > todays-date - - name: Restore cache for today's nightly. - uses: actions/cache@v2 + - name: luajit + uses: leafo/gh-actions-lua@v10 with: - path: | - build - key: ${{ runner.os }}-appimage-${{ hashFiles('todays-date') }} + luaVersion: "luajit-2.1.0-beta3" + + - name: luarocks + uses: leafo/gh-actions-luarocks@v4 - - name: Prepare + - name: build run: | - test -d build || { - mkdir -p build - wget https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage - chmod +x nvim.appimage - mv nvim.appimage ./build/nvim - } - mkdir -p ~/.local/share/nvim/site/pack/vendor/start - git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim - ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start - - name: Run tests + luarocks install plenary + + - name: run test + shell: bash run: | - export PATH="${PWD}/build/:${PATH}" - make test + luarocks install luacheck + luarocks install vusted + vusted ./test diff --git a/.gitignore b/.gitignore index 26dc7e5..f9a759c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,2 @@ -.zshrc.bak .direnv .pre-commit-config.yaml -/luarocks -/lua_modules -/.luarocks diff --git a/flake.lock b/flake.lock index 494b6b3..c2f2a63 100644 --- a/flake.lock +++ b/flake.lock @@ -1,38 +1,6 @@ { "nodes": { "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_2": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_3": { "flake": false, "locked": { "lastModified": 1673956053, @@ -53,11 +21,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1698882062, - "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "lastModified": 1701473968, + "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5", "type": "github" }, "original": { @@ -70,60 +38,6 @@ "inputs": { "systems": "systems" }, - "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, - "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_4": { - "inputs": { - "systems": "systems_4" - }, "locked": { "lastModified": 1685518550, "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", @@ -139,28 +53,6 @@ } }, "gitignore": { - "inputs": { - "nixpkgs": [ - "neorocks", - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1660459072, - "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "gitignore_2": { "inputs": { "nixpkgs": [ "pre-commit-hooks", @@ -184,11 +76,11 @@ "neodev-nvim": { "flake": false, "locked": { - "lastModified": 1698818751, - "narHash": "sha256-cTK0InESf30wlDY/Qo7NkBXumG43rAoS/fE4jjRUK44=", + "lastModified": 1703570758, + "narHash": "sha256-tIRhHXu2rFIlTtXcHjEzWjqB4SZpTZch13VOecuplSA=", "owner": "folke", "repo": "neodev.nvim", - "rev": "80487e4f7bfa11c2ef2a1b461963db019aad6a73", + "rev": "029899ea32d3dc8ed8c910ceca2ee5d16e566c11", "type": "github" }, "original": { @@ -197,59 +89,13 @@ "type": "github" } }, - "neorocks": { - "inputs": { - "flake-compat": "flake-compat", - "flake-utils": "flake-utils", - "neovim-nightly": "neovim-nightly", - "nixpkgs": "nixpkgs", - "pre-commit-hooks": "pre-commit-hooks" - }, - "locked": { - "lastModified": 1698470714, - "narHash": "sha256-QhIzRWfyU1otL36F5adyh1BEPfWp5v5L3N9opPSCm0Q=", - "owner": "nvim-neorocks", - "repo": "neorocks", - "rev": "76fccbd50534fccab7ab244cdb4a08eddb78b9bc", - "type": "github" - }, - "original": { - "owner": "nvim-neorocks", - "repo": "neorocks", - "type": "github" - } - }, - "neovim-nightly": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": [ - "neorocks", - "nixpkgs" - ] - }, - "locked": { - "dir": "contrib", - "lastModified": 1698460938, - "narHash": "sha256-+IDg4xXSooalZAin/zuY3dSY+zX8Sid65MfN+CWRq1Y=", - "owner": "neovim", - "repo": "neovim", - "rev": "ac353e87aecf02315d82a3ad22725d2bc8140f0c", - "type": "github" - }, - "original": { - "dir": "contrib", - "owner": "neovim", - "repo": "neovim", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1698336494, - "narHash": "sha256-sO72WDBKyijYD1GcKPlGsycKbMBiTJMBCnmOxLAs880=", + "lastModified": 1703499205, + "narHash": "sha256-lF9rK5mSUfIZJgZxC3ge40tp1gmyyOXZ+lRY3P8bfbg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "808c0d8c53c7ae50f82aca8e7df263225cf235bf", + "rev": "e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870", "type": "github" }, "original": { @@ -262,11 +108,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1698611440, - "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "lastModified": 1701253981, + "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", "type": "github" }, "original": { @@ -293,46 +139,14 @@ "type": "github" } }, - "nixpkgs-stable_2": { - "locked": { - "lastModified": 1685801374, - "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-23.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1699343069, - "narHash": "sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "ec750fd01963ab6b20ee1f0cb488754e8036d89d", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "plenary-nvim": { "flake": false, "locked": { - "lastModified": 1697031827, - "narHash": "sha256-zR44d9MowLG1lIbvrRaFTpO/HXKKrO6lbtZfvvTdx+o=", + "lastModified": 1701343040, + "narHash": "sha256-f8YVaXMG0ZyW6iotAgnftaYULnL69UPolRad6RTG27g=", "owner": "nvim-lua", "repo": "plenary.nvim", - "rev": "50012918b2fc8357b87cff2a7f7f0446e47da174", + "rev": "55d9fe89e33efd26f532ef20223e5f9430c8b0c0", "type": "github" }, "original": { @@ -343,45 +157,20 @@ }, "pre-commit-hooks": { "inputs": { - "flake-compat": "flake-compat_2", - "flake-utils": "flake-utils_3", + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", "gitignore": "gitignore", "nixpkgs": [ - "neorocks", "nixpkgs" ], "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1698227354, - "narHash": "sha256-Fi5H9jbaQLmLw9qBi/mkR33CoFjNbobo5xWdX4tKz1Q=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "bd38df3d508dfcdff52cd243d297f218ed2257bf", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "pre-commit-hooks_2": { - "inputs": { - "flake-compat": "flake-compat_3", - "flake-utils": "flake-utils_4", - "gitignore": "gitignore_2", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable_2" - }, - "locked": { - "lastModified": 1699271226, - "narHash": "sha256-8Jt1KW3xTjolD6c6OjJm9USx/jmL+VVmbooADCkdDfU=", + "lastModified": 1703426812, + "narHash": "sha256-aODSOH8Og8ne4JylPJn+hZ6lyv6K7vE5jFo4KAGIebM=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "ea758da1a6dcde6dc36db348ed690d09b9864128", + "rev": "7f35ec30d16b38fe0eed8005933f418d1a4693ee", "type": "github" }, "original": { @@ -394,10 +183,9 @@ "inputs": { "flake-parts": "flake-parts", "neodev-nvim": "neodev-nvim", - "neorocks": "neorocks", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs", "plenary-nvim": "plenary-nvim", - "pre-commit-hooks": "pre-commit-hooks_2", + "pre-commit-hooks": "pre-commit-hooks", "telescope-nvim": "telescope-nvim" } }, @@ -416,59 +204,14 @@ "type": "github" } }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "telescope-nvim": { "flake": false, "locked": { - "lastModified": 1699236417, - "narHash": "sha256-JZuEJKiWmoBC1KGjkgebi5zsWMyLmn+jSR633lHa2yQ=", + "lastModified": 1703697665, + "narHash": "sha256-HnRjfgJZ6DUcf79eibpmKNNsP8DMSPczD06ZoXiOtHk=", "owner": "nvim-telescope", "repo": "telescope.nvim", - "rev": "20bf20500c95208c3ac0ef07245065bf94dcab15", + "rev": "e0651458f2ced647f3ff3c89d5663244b3cf45af", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 70d84b8..4678ae5 100644 --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,6 @@ inputs = { flake-parts.url = "github:hercules-ci/flake-parts"; - neorocks. url = "github:nvim-neorocks/neorocks"; nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; pre-commit-hooks = { url = "github:cachix/pre-commit-hooks.nix"; @@ -56,28 +55,16 @@ _module.args.pkgs = import inputs.nixpkgs { inherit system; overlays = [ - inputs.neorocks.overlays.default ]; }; devShells = { default = pkgs.mkShell { name = "haskell-tools.nvim-shell"; inherit (pre-commit-check) shellHook; - buildInputs = - with pkgs; [ - neorocks - haskellPackages.neolua-bin - stylua - ] - #++ (with inputs.pre-commit-hooks.packages.${system}; [ - # alejandra - # lua-language-server - # stylua - # luacheck - # markdownlint-cli - #]) - ; - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath []; + buildInputs = with pkgs; [ + luajitPackages.vusted + stylua + ]; }; }; @@ -114,18 +101,6 @@ inherit (inputs) pre-commit-hooks; inherit self; }; - neorocks-test-stable = pkgs.callPackage ./nix/neorocks-test.nix { - name = "git-worktree-stable"; - inherit self; - nvim = pkgs.neovim-unwrapped; - inherit (config.packages) plenary-plugin; - }; - neorocks-test-unstable = pkgs.callPackage ./nix/neorocks-test.nix { - name = "git-worktree-nightly"; - inherit self; - nvim = pkgs.neovim-nightly; - inherit (config.packages) plenary-plugin; - }; }; }; }; From e31db85659158f6e1b6f1f75c66e6a8b18a36158 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 27 Dec 2023 23:13:27 -0500 Subject: [PATCH 11/33] chore: add name to commit-lint --- .github/workflows/ci.yml | 6 +----- .github/workflows/commit_lint.yml | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 076c33c..ed85d68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,13 +26,9 @@ jobs: - name: luarocks uses: leafo/gh-actions-luarocks@v4 - - name: build - run: | - luarocks install plenary - - name: run test shell: bash run: | luarocks install luacheck luarocks install vusted - vusted ./test + vusted diff --git a/.github/workflows/commit_lint.yml b/.github/workflows/commit_lint.yml index e1df4ca..1e5b5d8 100644 --- a/.github/workflows/commit_lint.yml +++ b/.github/workflows/commit_lint.yml @@ -1,3 +1,4 @@ +name: commit-lint on: [pull_request] jobs: lint-commits: From 625005d7ffa662b4de0bb785368e28835864a782 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 28 Dec 2023 13:54:07 -0500 Subject: [PATCH 12/33] ci: add plenary install --- .busted | 12 ------------ .github/workflows/ci.yml | 4 ++++ 2 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 .busted diff --git a/.busted b/.busted deleted file mode 100644 index 5d91aed..0000000 --- a/.busted +++ /dev/null @@ -1,12 +0,0 @@ -return { - _all = { - coverage = false, - lpath = "lua/?.lua;lua/?/init.lua;spec/?.lua;spec/?/init.lua", - }, - default = { - verbose = true - }, - tests = { - verbose = true - }, -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed85d68..89f96ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,10 @@ jobs: - name: luarocks uses: leafo/gh-actions-luarocks@v4 + - name: install plenary.nvim + run: | + git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim + - name: run test shell: bash run: | From 88bbd7e88b0503d33b559d5823f1a3c0f4824c9a Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 28 Dec 2023 14:32:02 -0500 Subject: [PATCH 13/33] chore: refactor tests to hopefully pass --- .github/workflows/ci.yml | 14 +++++++++++--- .luacheckrc | 17 ++++++++--------- Makefile | 4 +++- {spec => lua/git-worktree}/config_spec.lua | 0 {spec => lua/git-worktree}/git_spec.lua | 2 +- {spec => lua/git-worktree}/setup_spec.lua | 0 .../git-worktree/test/git_util.lua | 4 ++-- .../git-worktree/test/system_util.lua | 0 .../fixtures}/.repo/.git-orig/COMMIT_EDITMSG | 0 .../fixtures}/.repo/.git-orig/FETCH_HEAD | 0 {spec => test/fixtures}/.repo/.git-orig/HEAD | 0 {spec => test/fixtures}/.repo/.git-orig/config | 0 .../fixtures}/.repo/.git-orig/description | 0 .../.git-orig/hooks/applypatch-msg.sample | 0 .../.repo/.git-orig/hooks/commit-msg.sample | 0 .../.git-orig/hooks/fsmonitor-watchman.sample | 0 .../.repo/.git-orig/hooks/post-update.sample | 0 .../.git-orig/hooks/pre-applypatch.sample | 0 .../.repo/.git-orig/hooks/pre-commit.sample | 0 .../.git-orig/hooks/pre-merge-commit.sample | 0 .../.repo/.git-orig/hooks/pre-push.sample | 0 .../.repo/.git-orig/hooks/pre-rebase.sample | 0 .../.repo/.git-orig/hooks/pre-receive.sample | 0 .../.git-orig/hooks/prepare-commit-msg.sample | 0 .../.repo/.git-orig/hooks/update.sample | 0 {spec => test/fixtures}/.repo/.git-orig/index | Bin .../fixtures}/.repo/.git-orig/info/exclude | 0 .../fixtures}/.repo/.git-orig/logs/HEAD | 0 .../.repo/.git-orig/logs/refs/heads/featB | 0 .../.repo/.git-orig/logs/refs/heads/featC | 0 .../.repo/.git-orig/logs/refs/heads/master | 0 .../0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 | Bin .../1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 | Bin .../2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 | 0 .../30/a0f033a755629a8ef1561e7b7ece3750ce8a13 | Bin .../39/ba5d897e269fb97a17058423947603f010e702 | Bin .../3b/73d17c51c9b22ff9d4552e5bb56927776173b3 | Bin .../40/c09bafbe2555af7017dd08f027e4ae45db2879 | Bin .../61/fcdbfa0b2af3418651b55d003c05c8e128d22e | Bin .../91/b5884361b690f3bf1ba2edc9145a01d651a920 | Bin .../fixtures}/.repo/.git-orig/refs/heads/featB | 0 .../fixtures}/.repo/.git-orig/refs/heads/featC | 0 .../.repo/.git-orig/refs/heads/master | 0 {spec => test/fixtures}/.repo/A.txt | 0 44 files changed, 25 insertions(+), 16 deletions(-) rename {spec => lua/git-worktree}/config_spec.lua (100%) rename {spec => lua/git-worktree}/git_spec.lua (96%) rename {spec => lua/git-worktree}/setup_spec.lua (100%) rename spec/util/git_harness.lua => lua/git-worktree/test/git_util.lua (93%) rename spec/util/system.lua => lua/git-worktree/test/system_util.lua (100%) rename {spec => test/fixtures}/.repo/.git-orig/COMMIT_EDITMSG (100%) rename {spec => test/fixtures}/.repo/.git-orig/FETCH_HEAD (100%) rename {spec => test/fixtures}/.repo/.git-orig/HEAD (100%) rename {spec => test/fixtures}/.repo/.git-orig/config (100%) rename {spec => test/fixtures}/.repo/.git-orig/description (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/applypatch-msg.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/commit-msg.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/fsmonitor-watchman.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/post-update.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/pre-applypatch.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/pre-commit.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/pre-merge-commit.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/pre-push.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/pre-rebase.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/pre-receive.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/prepare-commit-msg.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/hooks/update.sample (100%) rename {spec => test/fixtures}/.repo/.git-orig/index (100%) rename {spec => test/fixtures}/.repo/.git-orig/info/exclude (100%) rename {spec => test/fixtures}/.repo/.git-orig/logs/HEAD (100%) rename {spec => test/fixtures}/.repo/.git-orig/logs/refs/heads/featB (100%) rename {spec => test/fixtures}/.repo/.git-orig/logs/refs/heads/featC (100%) rename {spec => test/fixtures}/.repo/.git-orig/logs/refs/heads/master (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e (100%) rename {spec => test/fixtures}/.repo/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 (100%) rename {spec => test/fixtures}/.repo/.git-orig/refs/heads/featB (100%) rename {spec => test/fixtures}/.repo/.git-orig/refs/heads/featC (100%) rename {spec => test/fixtures}/.repo/.git-orig/refs/heads/master (100%) rename {spec => test/fixtures}/.repo/A.txt (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89f96ca..4c2d1f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,11 +28,19 @@ jobs: - name: install plenary.nvim run: | - git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim + git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary + # git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim - - name: run test + - name: setup tools shell: bash run: | luarocks install luacheck luarocks install vusted - vusted + + - name: Run tests + shell: bash + env: + VUSTED_NVIM: ${{ steps.vim.outputs.executable }} + VUSTED_ARGS: "--headless" + run: | + make test diff --git a/.luacheckrc b/.luacheckrc index fc60a60..fe54381 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1,10 +1,9 @@ -self = false - -ignore = { -} -read_globals = { - "vim", - "describe", - "it", - "assert" +globals = { + 'vim', + 'describe', + 'it', + 'before_each', + 'after_each', + 'assert', + 'async', } diff --git a/Makefile b/Makefile index e5f2bc2..553ca06 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,4 @@ +# GIT_WORKTREE_NVIM_LOG=fatal +.PHONY: test test: - GIT_WORKTREE_NVIM_LOG=fatal nvim --headless --noplugin -u tests/minimal_init.vim -c "PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal_init.vim' }" + vusted --output=gtest ./lua diff --git a/spec/config_spec.lua b/lua/git-worktree/config_spec.lua similarity index 100% rename from spec/config_spec.lua rename to lua/git-worktree/config_spec.lua diff --git a/spec/git_spec.lua b/lua/git-worktree/git_spec.lua similarity index 96% rename from spec/git_spec.lua rename to lua/git-worktree/git_spec.lua index f3ae6b9..0730c87 100644 --- a/spec/git_spec.lua +++ b/lua/git-worktree/git_spec.lua @@ -1,4 +1,4 @@ -local git_harness = require('util.git_harness') +local git_harness = require('git-worktree.test.git_util') local gwt_git = require('git-worktree.git') local Status = require('git-worktree.status') diff --git a/spec/setup_spec.lua b/lua/git-worktree/setup_spec.lua similarity index 100% rename from spec/setup_spec.lua rename to lua/git-worktree/setup_spec.lua diff --git a/spec/util/git_harness.lua b/lua/git-worktree/test/git_util.lua similarity index 93% rename from spec/util/git_harness.lua rename to lua/git-worktree/test/git_util.lua index d797214..3ba318d 100644 --- a/spec/util/git_harness.lua +++ b/lua/git-worktree/test/git_util.lua @@ -1,4 +1,4 @@ -local system = require('util.system') +local system = require('git-worktree.test.system_util') local M = {} @@ -11,7 +11,7 @@ function M.setup_origin_repo() local workspace_dir = system.create_temp_dir('workspace-dir') vim.api.nvim_set_current_dir(vim.fn.getcwd()) - system.run('cp -r spec/.repo ' .. workspace_dir) + system.run('cp -r test/fixtures/.repo ' .. workspace_dir) vim.api.nvim_set_current_dir(workspace_dir) system.run([[ mv .repo/.git-orig ./.git diff --git a/spec/util/system.lua b/lua/git-worktree/test/system_util.lua similarity index 100% rename from spec/util/system.lua rename to lua/git-worktree/test/system_util.lua diff --git a/spec/.repo/.git-orig/COMMIT_EDITMSG b/test/fixtures/.repo/.git-orig/COMMIT_EDITMSG similarity index 100% rename from spec/.repo/.git-orig/COMMIT_EDITMSG rename to test/fixtures/.repo/.git-orig/COMMIT_EDITMSG diff --git a/spec/.repo/.git-orig/FETCH_HEAD b/test/fixtures/.repo/.git-orig/FETCH_HEAD similarity index 100% rename from spec/.repo/.git-orig/FETCH_HEAD rename to test/fixtures/.repo/.git-orig/FETCH_HEAD diff --git a/spec/.repo/.git-orig/HEAD b/test/fixtures/.repo/.git-orig/HEAD similarity index 100% rename from spec/.repo/.git-orig/HEAD rename to test/fixtures/.repo/.git-orig/HEAD diff --git a/spec/.repo/.git-orig/config b/test/fixtures/.repo/.git-orig/config similarity index 100% rename from spec/.repo/.git-orig/config rename to test/fixtures/.repo/.git-orig/config diff --git a/spec/.repo/.git-orig/description b/test/fixtures/.repo/.git-orig/description similarity index 100% rename from spec/.repo/.git-orig/description rename to test/fixtures/.repo/.git-orig/description diff --git a/spec/.repo/.git-orig/hooks/applypatch-msg.sample b/test/fixtures/.repo/.git-orig/hooks/applypatch-msg.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/applypatch-msg.sample rename to test/fixtures/.repo/.git-orig/hooks/applypatch-msg.sample diff --git a/spec/.repo/.git-orig/hooks/commit-msg.sample b/test/fixtures/.repo/.git-orig/hooks/commit-msg.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/commit-msg.sample rename to test/fixtures/.repo/.git-orig/hooks/commit-msg.sample diff --git a/spec/.repo/.git-orig/hooks/fsmonitor-watchman.sample b/test/fixtures/.repo/.git-orig/hooks/fsmonitor-watchman.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/fsmonitor-watchman.sample rename to test/fixtures/.repo/.git-orig/hooks/fsmonitor-watchman.sample diff --git a/spec/.repo/.git-orig/hooks/post-update.sample b/test/fixtures/.repo/.git-orig/hooks/post-update.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/post-update.sample rename to test/fixtures/.repo/.git-orig/hooks/post-update.sample diff --git a/spec/.repo/.git-orig/hooks/pre-applypatch.sample b/test/fixtures/.repo/.git-orig/hooks/pre-applypatch.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/pre-applypatch.sample rename to test/fixtures/.repo/.git-orig/hooks/pre-applypatch.sample diff --git a/spec/.repo/.git-orig/hooks/pre-commit.sample b/test/fixtures/.repo/.git-orig/hooks/pre-commit.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/pre-commit.sample rename to test/fixtures/.repo/.git-orig/hooks/pre-commit.sample diff --git a/spec/.repo/.git-orig/hooks/pre-merge-commit.sample b/test/fixtures/.repo/.git-orig/hooks/pre-merge-commit.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/pre-merge-commit.sample rename to test/fixtures/.repo/.git-orig/hooks/pre-merge-commit.sample diff --git a/spec/.repo/.git-orig/hooks/pre-push.sample b/test/fixtures/.repo/.git-orig/hooks/pre-push.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/pre-push.sample rename to test/fixtures/.repo/.git-orig/hooks/pre-push.sample diff --git a/spec/.repo/.git-orig/hooks/pre-rebase.sample b/test/fixtures/.repo/.git-orig/hooks/pre-rebase.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/pre-rebase.sample rename to test/fixtures/.repo/.git-orig/hooks/pre-rebase.sample diff --git a/spec/.repo/.git-orig/hooks/pre-receive.sample b/test/fixtures/.repo/.git-orig/hooks/pre-receive.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/pre-receive.sample rename to test/fixtures/.repo/.git-orig/hooks/pre-receive.sample diff --git a/spec/.repo/.git-orig/hooks/prepare-commit-msg.sample b/test/fixtures/.repo/.git-orig/hooks/prepare-commit-msg.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/prepare-commit-msg.sample rename to test/fixtures/.repo/.git-orig/hooks/prepare-commit-msg.sample diff --git a/spec/.repo/.git-orig/hooks/update.sample b/test/fixtures/.repo/.git-orig/hooks/update.sample similarity index 100% rename from spec/.repo/.git-orig/hooks/update.sample rename to test/fixtures/.repo/.git-orig/hooks/update.sample diff --git a/spec/.repo/.git-orig/index b/test/fixtures/.repo/.git-orig/index similarity index 100% rename from spec/.repo/.git-orig/index rename to test/fixtures/.repo/.git-orig/index diff --git a/spec/.repo/.git-orig/info/exclude b/test/fixtures/.repo/.git-orig/info/exclude similarity index 100% rename from spec/.repo/.git-orig/info/exclude rename to test/fixtures/.repo/.git-orig/info/exclude diff --git a/spec/.repo/.git-orig/logs/HEAD b/test/fixtures/.repo/.git-orig/logs/HEAD similarity index 100% rename from spec/.repo/.git-orig/logs/HEAD rename to test/fixtures/.repo/.git-orig/logs/HEAD diff --git a/spec/.repo/.git-orig/logs/refs/heads/featB b/test/fixtures/.repo/.git-orig/logs/refs/heads/featB similarity index 100% rename from spec/.repo/.git-orig/logs/refs/heads/featB rename to test/fixtures/.repo/.git-orig/logs/refs/heads/featB diff --git a/spec/.repo/.git-orig/logs/refs/heads/featC b/test/fixtures/.repo/.git-orig/logs/refs/heads/featC similarity index 100% rename from spec/.repo/.git-orig/logs/refs/heads/featC rename to test/fixtures/.repo/.git-orig/logs/refs/heads/featC diff --git a/spec/.repo/.git-orig/logs/refs/heads/master b/test/fixtures/.repo/.git-orig/logs/refs/heads/master similarity index 100% rename from spec/.repo/.git-orig/logs/refs/heads/master rename to test/fixtures/.repo/.git-orig/logs/refs/heads/master diff --git a/spec/.repo/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 b/test/fixtures/.repo/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 similarity index 100% rename from spec/.repo/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 rename to test/fixtures/.repo/.git-orig/objects/0b/4012bdb8b7f16ec2c7490276b071a85dbf86e9 diff --git a/spec/.repo/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 b/test/fixtures/.repo/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 similarity index 100% rename from spec/.repo/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 rename to test/fixtures/.repo/.git-orig/objects/1a/d41d73bf6e2f4d929f0ab5e3098e5e5b31f8e2 diff --git a/spec/.repo/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 b/test/fixtures/.repo/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 similarity index 100% rename from spec/.repo/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 rename to test/fixtures/.repo/.git-orig/objects/2a/fa41f6d9a4e4dc25e9088e402fe7ba35b95a10 diff --git a/spec/.repo/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 b/test/fixtures/.repo/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 similarity index 100% rename from spec/.repo/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 rename to test/fixtures/.repo/.git-orig/objects/30/a0f033a755629a8ef1561e7b7ece3750ce8a13 diff --git a/spec/.repo/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 b/test/fixtures/.repo/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 similarity index 100% rename from spec/.repo/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 rename to test/fixtures/.repo/.git-orig/objects/39/ba5d897e269fb97a17058423947603f010e702 diff --git a/spec/.repo/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 b/test/fixtures/.repo/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 similarity index 100% rename from spec/.repo/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 rename to test/fixtures/.repo/.git-orig/objects/3b/73d17c51c9b22ff9d4552e5bb56927776173b3 diff --git a/spec/.repo/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 b/test/fixtures/.repo/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 similarity index 100% rename from spec/.repo/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 rename to test/fixtures/.repo/.git-orig/objects/40/c09bafbe2555af7017dd08f027e4ae45db2879 diff --git a/spec/.repo/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e b/test/fixtures/.repo/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e similarity index 100% rename from spec/.repo/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e rename to test/fixtures/.repo/.git-orig/objects/61/fcdbfa0b2af3418651b55d003c05c8e128d22e diff --git a/spec/.repo/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 b/test/fixtures/.repo/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 similarity index 100% rename from spec/.repo/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 rename to test/fixtures/.repo/.git-orig/objects/91/b5884361b690f3bf1ba2edc9145a01d651a920 diff --git a/spec/.repo/.git-orig/refs/heads/featB b/test/fixtures/.repo/.git-orig/refs/heads/featB similarity index 100% rename from spec/.repo/.git-orig/refs/heads/featB rename to test/fixtures/.repo/.git-orig/refs/heads/featB diff --git a/spec/.repo/.git-orig/refs/heads/featC b/test/fixtures/.repo/.git-orig/refs/heads/featC similarity index 100% rename from spec/.repo/.git-orig/refs/heads/featC rename to test/fixtures/.repo/.git-orig/refs/heads/featC diff --git a/spec/.repo/.git-orig/refs/heads/master b/test/fixtures/.repo/.git-orig/refs/heads/master similarity index 100% rename from spec/.repo/.git-orig/refs/heads/master rename to test/fixtures/.repo/.git-orig/refs/heads/master diff --git a/spec/.repo/A.txt b/test/fixtures/.repo/A.txt similarity index 100% rename from spec/.repo/A.txt rename to test/fixtures/.repo/A.txt From 7faefb595b56d4e32020ddad1d53089e75da5374 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 28 Dec 2023 20:41:10 -0500 Subject: [PATCH 14/33] refactor: lost code --- flake.nix | 1 + lua/git-worktree/git.lua | 130 +++++++++++++++------- lua/git-worktree/git_spec.lua | 172 ++++++++++++++++++++++++++--- lua/git-worktree/init.lua | 128 ++++++++------------- lua/git-worktree/test/git_util.lua | 2 +- lua/git-worktree/worktree_spec.lua | 55 +++++++++ 6 files changed, 345 insertions(+), 143 deletions(-) create mode 100644 lua/git-worktree/worktree_spec.lua diff --git a/flake.nix b/flake.nix index 4678ae5..b0e4798 100644 --- a/flake.nix +++ b/flake.nix @@ -62,6 +62,7 @@ name = "haskell-tools.nvim-shell"; inherit (pre-commit-check) shellHook; buildInputs = with pkgs; [ + luajitPackages.luacheck luajitPackages.vusted stylua ]; diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index c890939..d76bb3c 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -1,12 +1,66 @@ local Job = require('plenary').job --- --local Path = require("plenary.path") --- local Status = require("git-worktree.status") +local Path = require('plenary.path') +-- local Status = require('git-worktree.status') -- -- local status = Status:new() -- ---@class GitWorktreeGitOps local M = {} --- + +-- A lot of this could be cleaned up if there was better job -> job -> function +-- communication. That should be doable here in the near future +--- +---@param path_str string path to the worktree to check. if relative, then path from the git root dir +---@param cb any +function M.has_worktree(path_str, cb) + local found = false + local path = Path:new(path_str) + local git_worktree_root = M.gitroot_dir() + + if path_str == '.' then + path_str = vim.loop.cwd() + path = Path:new(path_str) + end + + local job = Job:new { + 'git', + 'worktree', + 'list', + on_stdout = function(_, data) + local list_data = {} + for section in data:gmatch('%S+') do + table.insert(list_data, section) + end + print(vim.inspect(list_data)) + + data = list_data[1] + + local start + if path:is_absolute() then + start = data == path_str + else + local worktree_path = + Path:new(string.format('%s' .. Path.path.sep .. '%s', git_worktree_root, path_str)) + worktree_path = worktree_path:absolute() + start = data == worktree_path + end + + -- TODO: This is clearly a hack (do not think we need this anymore?) + --local start_with_head = string.find(data, string.format('[heads/%s]', path), 1, true) + found = found or start + end, + cwd = vim.loop.cwd(), + } + + job:after(function() + cb(found) + end) + + -- TODO: I really don't want status's spread everywhere... seems bad + --status:next_status('Checking for worktree ' .. path) + job:start() +end + -- --- @return boolean -- function M.is_bare_repo() -- local inside_worktree_job = Job:new({ @@ -54,13 +108,42 @@ local M = {} -- return false -- end -- end --- + +--- @return string|nil +function M.gitroot_dir() + local job = Job:new { + 'git', + 'rev-parse', + '--path-format=absolute', + '--git-common-dir', + cwd = vim.loop.cwd(), + -- on_stderr = function(_, data) + -- status:log().info('ERROR: ' .. data) + -- end, + } + + local stdout, code = job:sync() + if code ~= 0 then + -- status:log().error( + -- 'Error in determining the git root dir: code:' + -- .. tostring(code) + -- .. ' out: ' + -- .. table.concat(stdout, '') + -- .. '.' + -- ) + return nil + end + + return table.concat(stdout, '') +end + -- @param is_worktree boolean --- @return string|nil -function M.find_git_dir() +function M.toplevel_dir() local job = Job:new { 'git', 'rev-parse', + '--path-format=absolute', '--show-toplevel', cwd = vim.loop.cwd(), -- on_stderr = function(_, data) @@ -80,44 +163,9 @@ function M.find_git_dir() return nil end - stdout = table.concat(stdout, '') - -- status:log().info('cwd: ' .. vim.loop.cwd()) - -- status:log().info('git root dir: ' .. stdout) - - -- if is_worktree then - -- -- if in worktree git dir returns absolute path - -- - -- -- try to find the dot git folder (non-bare repo) - -- local git_dir = Path:new(stdout) - -- local has_dot_git = false - -- for _, dir in ipairs(git_dir:_split()) do - -- if dir == ".git" then - -- has_dot_git = true - -- break - -- end - -- end - -- - -- if has_dot_git then - -- if stdout == ".git" then - -- return vim.loop.cwd() - -- else - -- local start = stdout:find("%.git") - -- return stdout:sub(1, start - 2) - -- end - -- else - -- local start = stdout:find("/worktrees/") - -- return stdout:sub(0, start - 1) - -- end - -- elseif stdout == "." then - -- -- we are in the root git dir - -- return vim.loop.cwd() - -- else - -- if not in worktree git dir should be absolute - return stdout - -- end + return table.concat(stdout, '') end --- -- --- @return string|nil -- function M.find_git_toplevel() -- local find_toplevel_job = Job:new({ diff --git a/lua/git-worktree/git_spec.lua b/lua/git-worktree/git_spec.lua index 0730c87..76efc2f 100644 --- a/lua/git-worktree/git_spec.lua +++ b/lua/git-worktree/git_spec.lua @@ -4,40 +4,180 @@ local Status = require('git-worktree.status') local status = Status:new() --- luacheck: globals repo_dir +-- local wait_for_result = function(job, result) +-- if type(result) == 'string' then +-- result = { result } +-- end +-- vim.wait(1000, function() +-- return tables_equal(job:result(), result) +-- end) +-- end + +-- luacheck: globals repo_dir worktree_dir describe('git-worktree git operations', function() - describe('finds git toplevel in normal repo', function() + describe('in normal repo', function() before_each(function() repo_dir = git_harness.prepare_repo() status:reset(0) end) - it('Public API is available after setup.', function() - local ret_git_dir = gwt_git.find_git_dir() - assert.are.same(ret_git_dir, repo_dir) + it('finds toplevel.', function() + local ret = gwt_git.toplevel_dir() + assert.are.same(ret, repo_dir) + end) + it('finds root git dir.', function() + local ret = gwt_git.gitroot_dir() + local root_repo_dir = repo_dir .. '/.git' + assert.are.same(ret, root_repo_dir) + end) + it('has_worktree valid absolute.', function() + local completed = false + local ret = false + + gwt_git.has_worktree(repo_dir, function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(true, ret) + end) + it('has_worktree valid relative.', function() + local completed = false + local ret = false + + gwt_git.has_worktree('..', function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(true, ret) + end) + it('has_worktree invalid absolute.', function() + local completed = false + local ret = false + + gwt_git.has_worktree('/tmp', function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(false, ret) + end) + it('has_worktree invalid relative.', function() + local completed = false + local ret = false + + gwt_git.has_worktree('../foo', function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(false, ret) end) end) - describe('finds git toplevel in bare repo', function() + describe('in bare repo', function() before_each(function() repo_dir = git_harness.prepare_repo_bare() status:reset(0) end) - it('no toplevel in a bare repo', function() - local ret_git_dir = gwt_git.find_git_dir() - assert.are.same(ret_git_dir, nil) + it('finds toplevel', function() + local ret = gwt_git.toplevel_dir() + assert.are.same(ret, nil) + end) + it('finds root git dir.', function() + local ret_git_dir = gwt_git.gitroot_dir() + assert.are.same(ret_git_dir, repo_dir) + end) + it('has_worktree valid absolute.', function() + local completed = false + local ret = false + + gwt_git.has_worktree(repo_dir, function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(true, ret) + end) + it('has_worktree valid relative.', function() + local completed = false + local ret = false + + gwt_git.has_worktree('.', function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(true, ret) + end) + it('has_worktree invalid absolute.', function() + local completed = false + local ret = false + + gwt_git.has_worktree('/tmp', function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(false, ret) + end) + it('has_worktree invalid relative.', function() + local completed = false + local ret = false + + gwt_git.has_worktree('../foo', function(found) + completed = true + ret = found + end) + + vim.fn.wait(10000, function() + return completed + end, 1000) + + assert.are.same(false, ret) end) end) - describe('finds git toplevel in worktree repo', function() + describe('in worktree repo', function() before_each(function() - repo_dir = git_harness.prepare_repo_worktree() + repo_dir, worktree_dir = git_harness.prepare_repo_worktree() status:reset(0) end) - it('Public API is available after setup.', function() - local ret_git_dir = gwt_git.find_git_dir() - status:status('ret_git_dir: ' .. ret_git_dir .. '.') - status:status('repo_dir : ' .. repo_dir .. '.') - assert.are.same(ret_git_dir, repo_dir) + it('finds toplevel.', function() + local ret = gwt_git.toplevel_dir() + assert.are.same(ret, worktree_dir) + end) + it('finds root git dir.', function() + local ret = gwt_git.gitroot_dir() + assert.are.same(ret, repo_dir) end) end) end) diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index 5155367..02ca64b 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -1,9 +1,9 @@ -- local Job = require("plenary.job") --- local Path = require("plenary.path") +local Path = require('plenary.path') -- local Enum = require("git-worktree.enum") --- local Config = require('git-worktree.config') --- local Git = require("git-worktree.git") +local Config = require('git-worktree.config') +local Git = require('git-worktree.git') -- local Hooks = require("git-worktree.hooks") local Status = require('git-worktree.status') @@ -13,7 +13,6 @@ local status = Status:new() -- local on_change_callbacks = {} ---@class GitWorktree ----@field config GitWorktreeConfig local M = {} @@ -22,28 +21,46 @@ function M.setup(opts) require('git-worktree.config').setup(opts) end --- local function change_dirs(path) --- local worktree_path = M.get_worktree_path(path) --- --- local previous_worktree = current_worktree_path --- --- -- vim.loop.chdir(worktree_path) --- if Path:new(worktree_path):exists() then --- local cmd = string.format("%s %s", M._config.change_directory_command, worktree_path) --- status:log().debug("Changing to directory " .. worktree_path) --- vim.cmd(cmd) --- current_worktree_path = worktree_path --- else --- status:error("Could not chang to directory: " .. worktree_path) --- end --- --- if M._config.clearjumps_on_change then --- status:log().debug("Clearing jumps") --- vim.cmd("clearjumps") --- end --- --- return previous_worktree --- end +local function change_dirs(path) + local worktree_path = M.get_worktree_path(path) + + local previous_worktree = Git.toplevel_dir() + + -- vim.loop.chdir(worktree_path) + if Path:new(worktree_path):exists() then + local cmd = string.format('%s %s', Config.options.change_directory_command, worktree_path) + -- status:log().debug('Changing to directory ' .. worktree_path) + vim.cmd(cmd) + else + status:error('Could not chang to directory: ' .. worktree_path) + end + + if M._config.clearjumps_on_change then + -- status:log().debug('Clearing jumps') + vim.cmd('clearjumps') + end + + return previous_worktree +end + +--Switch the current worktree +---@param path string +M.switch_worktree = function(path) + status:reset(2) + status:status(path) + + Git.has_worktree(path, function(found) + if not found then + status:error('worktree does not exists, please create it first ' .. path) + end + + vim.schedule(function() + -- local prev_path = change_dirs(path) + change_dirs(path) + -- Hooks.emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) + end) + end) +end -- -- local function create_worktree_job(path, branch, found_branch) -- local worktree_add_cmd = "git" @@ -68,48 +85,6 @@ end -- }) -- end -- --- -- A lot of this could be cleaned up if there was better job -> job -> function --- -- communication. That should be doable here in the near future --- local function has_worktree(path, cb) --- local found = false --- local plenary_path = Path:new(path) --- --- local job = Job:new({ --- "git", --- "worktree", --- "list", --- on_stdout = function(_, data) --- local list_data = {} --- for section in data:gmatch("%S+") do --- table.insert(list_data, section) --- end --- --- data = list_data[1] --- --- local start --- if plenary_path:is_absolute() then --- start = data == path --- else --- local worktree_path = Path:new(string.format("%s" .. Path.path.sep .. "%s", git_worktree_root, path)) --- worktree_path = worktree_path:absolute() --- start = data == worktree_path --- end --- --- -- TODO: This is clearly a hack (do not think we need this anymore?) --- local start_with_head = string.find(data, string.format("[heads/%s]", path), 1, true) --- found = found or start or start_with_head --- end, --- cwd = git_worktree_root, --- }) --- --- job:after(function() --- cb(found) --- end) --- --- -- TODO: I really don't want status's spread everywhere... seems bad --- status:next_status("Checking for worktree " .. path) --- job:start() --- end -- -- local function failure(from, cmd, path, soft_error) -- return function(e) @@ -247,23 +222,6 @@ end -- end -- ---Switch the current worktree ----@param path string -M.switch_worktree = function(path) - status:reset(2) - status:status(path) - -- M.setup_git_info() - -- has_worktree(path, function(found) - -- if not found then - -- status:error("worktree does not exists, please create it first " .. path) - -- end - -- - -- vim.schedule(function() - -- local prev_path = change_dirs(path) - -- Hooks.emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) - -- end) - -- end) -end -- -- M.delete_worktree = function(path, force, opts) -- if not opts then diff --git a/lua/git-worktree/test/git_util.lua b/lua/git-worktree/test/git_util.lua index 3ba318d..1902b75 100644 --- a/lua/git-worktree/test/git_util.lua +++ b/lua/git-worktree/test/git_util.lua @@ -58,7 +58,7 @@ function M.prepare_repo_worktree() system.run('git worktree add wt master') local worktree_dir = working_dir .. '/wt' vim.api.nvim_set_current_dir(worktree_dir) - return worktree_dir + return working_dir, worktree_dir end return M diff --git a/lua/git-worktree/worktree_spec.lua b/lua/git-worktree/worktree_spec.lua new file mode 100644 index 0000000..b962804 --- /dev/null +++ b/lua/git-worktree/worktree_spec.lua @@ -0,0 +1,55 @@ +-- local Status = require('git-worktree.status') + +-- local status = Status:new() + +-- luacheck: globals repo_dir +describe('git-worktree', function() + -- local completed_create = false + -- local completed_switch = false + -- local completed_delete = false + + -- local reset_variables = function() + -- -- completed_create = false + -- completed_switch = false + -- -- completed_delete = false + -- end + + -- before_each(function() + -- reset_variables() + -- git_worktree.on_tree_change(function(op, _, _) + -- -- if op == git_worktree.Operations.Create then + -- -- completed_create = true + -- -- end + -- if op == git_worktree.Operations.Switch then + -- completed_switch = true + -- end + -- -- if op == git_worktree.Operations.Delete then + -- -- completed_delete = true + -- -- end + -- end) + -- end) + + -- after_each(function() + -- -- git_worktree.reset() + -- end) + + describe('Switch', function() + describe('bare repo', function() + -- before_each(function() + -- repo_dir, worktree_dir = git_harness.prepare_repo_worktree() + -- end) + it('from a bare repo with one worktree, able to switch to worktree (relative path)', function() + -- local path = 'master' + -- git_worktree.switch_worktree(path) + -- + -- vim.fn.wait(10000, function() + -- return completed_switch + -- end, 1000) + -- + -- -- Check to make sure directory was switched + -- assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) + assert.are.same(vim.loop.cwd(), vim.loop.cwd()) + end) + end) + end) +end) From 906ba5258211f11d6f9624aeef893a3b99808571 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Fri, 29 Dec 2023 00:23:28 -0500 Subject: [PATCH 15/33] refactor: basic switch working --- Makefile | 4 ++ lua/git-worktree/config.lua | 39 +++++++++--- lua/git-worktree/config_spec.lua | 10 +-- lua/git-worktree/git.lua | 1 - lua/git-worktree/git_spec.lua | 11 ++++ lua/git-worktree/hooks.lua | 39 ++++++++++++ lua/git-worktree/init.lua | 97 ++++++++++++++++++------------ lua/git-worktree/logger.lua | 59 ++++++++++++++++++ lua/git-worktree/test/git_util.lua | 20 +++++- lua/git-worktree/worktree_spec.lua | 72 ++++++++++++---------- 10 files changed, 264 insertions(+), 88 deletions(-) create mode 100644 lua/git-worktree/logger.lua diff --git a/Makefile b/Makefile index 553ca06..f85615b 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,7 @@ +.PHONY: lint +lint: + luacheck ./lua + # GIT_WORKTREE_NVIM_LOG=fatal .PHONY: test test: diff --git a/lua/git-worktree/config.lua b/lua/git-worktree/config.lua index 90cfd58..73f75e1 100644 --- a/lua/git-worktree/config.lua +++ b/lua/git-worktree/config.lua @@ -1,23 +1,48 @@ local M = {} ----@class GitWorktree.Config +---@class GitWorktreeConfig local defaults = { + + -- command to change directory on your OS. + -- + --- @type string change_directory_command = 'cd', + + -- ????? + -- + --- @type boolean update_on_change = true, + + -- ???? + -- + --- @type string update_on_change_command = 'e .', + + -- clear jump list on change + -- + --- @type boolean clearjumps_on_change = true, + + -- confirm telescope deletions + -- + --- @type boolean confirm_telescope_deletions = true, + + -- ???? autopush worktree to origin + -- + --- @type boolean autopush = false, } ----@type GitWorktree.Config -M.options = {} +--- @return GitWorktreeConfig +M._get_defaults = function() + return defaults +end ----@param opts? GitWorktree.Config +---@param opts? GitWorktreeConfig function M.setup(opts) - M.options = vim.tbl_deep_extend('force', defaults, opts or {}) + local config = vim.tbl_deep_extend('force', vim.deepcopy(defaults), opts or {}) + return config end -M.setup() - return M diff --git a/lua/git-worktree/config_spec.lua b/lua/git-worktree/config_spec.lua index 7eae061..c054fb9 100644 --- a/lua/git-worktree/config_spec.lua +++ b/lua/git-worktree/config_spec.lua @@ -3,16 +3,16 @@ local stub = require('luassert.stub') describe('config', function() local notify_once = stub(vim, 'notify_once') local notify = stub(vim, 'notify') + local Config = require('git-worktree.config') it('returns the default config', function() - local Config = require('git-worktree.config') - assert.truthy(Config.options.change_directory_command) + local df = Config._get_defaults() + assert.truthy(df.change_directory_command) end) it('can have configuration applied', function() - local Config = require('git-worktree.config') - Config.setup { change_directory_command = 'test' } - assert.equals(Config.options.change_directory_command, 'test') + local cfg = Config.setup { change_directory_command = 'test' } + assert.equals(cfg.change_directory_command, 'test') end) it('No notifications at startup.', function() diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index d76bb3c..f197608 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -31,7 +31,6 @@ function M.has_worktree(path_str, cb) for section in data:gmatch('%S+') do table.insert(list_data, section) end - print(vim.inspect(list_data)) data = list_data[1] diff --git a/lua/git-worktree/git_spec.lua b/lua/git-worktree/git_spec.lua index 76efc2f..1e1ec0a 100644 --- a/lua/git-worktree/git_spec.lua +++ b/lua/git-worktree/git_spec.lua @@ -13,6 +13,8 @@ local status = Status:new() -- end) -- end +local cwd = vim.fn.getcwd() + -- luacheck: globals repo_dir worktree_dir describe('git-worktree git operations', function() describe('in normal repo', function() @@ -20,6 +22,9 @@ describe('git-worktree git operations', function() repo_dir = git_harness.prepare_repo() status:reset(0) end) + after_each(function() + vim.api.nvim_command('cd ' .. cwd) + end) it('finds toplevel.', function() local ret = gwt_git.toplevel_dir() assert.are.same(ret, repo_dir) @@ -96,6 +101,9 @@ describe('git-worktree git operations', function() repo_dir = git_harness.prepare_repo_bare() status:reset(0) end) + after_each(function() + vim.api.nvim_command('cd ' .. cwd) + end) it('finds toplevel', function() local ret = gwt_git.toplevel_dir() assert.are.same(ret, nil) @@ -171,6 +179,9 @@ describe('git-worktree git operations', function() repo_dir, worktree_dir = git_harness.prepare_repo_worktree() status:reset(0) end) + after_each(function() + vim.api.nvim_command('cd ' .. cwd) + end) it('finds toplevel.', function() local ret = gwt_git.toplevel_dir() assert.are.same(ret, worktree_dir) diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 495fa54..80624e9 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -2,10 +2,49 @@ -- local Status = require("git-worktree.status") -- local status = Status:new() +--- @class GitWorkTreeHook +--- @field SWITCH? fun(...): nil + --- @class GitWorktreeHooks +--- @field hooks GitWorktreeHook[] +local GitWorktreeHooks = {} + +GitWorktreeHooks.__index = GitWorktreeHooks + +function GitWorktreeHooks:new() + return setmetatable({ + hooks = {}, + }, self) +end + +---@param hook GitWorktreeHook +function GitWorktreeHooks:add_listener(hook) + table.insert(self.hooks, hook) +end + +function GitWorktreeHooks:clear_listener() + self.hooks = {} +end + +---@param type string +---@param ... any +function GitWorktreeHooks:emit(type, ...) + for _, cb in ipairs(self.hooks) do + print(type) + if cb[type] then + cb[type](...) + end + end +end local M = {} +M.hooks = GitWorktreeHooks:new() + +M.hook_event_names = { + SWITCH = 'SWITCH', +} + -- function M.on_tree_change_handler(op, metadata) -- if M._config.update_on_change then -- if op == Enum.Operations.Switch then diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index 02ca64b..ae1d296 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -1,63 +1,90 @@ --- local Job = require("plenary.job") local Path = require('plenary.path') --- local Enum = require("git-worktree.enum") local Config = require('git-worktree.config') local Git = require('git-worktree.git') --- local Hooks = require("git-worktree.hooks") -local Status = require('git-worktree.status') +local Hooks = require('git-worktree.hooks') +local Log = require('git-worktree.logger') -local status = Status:new() --- local git_worktree_root = nil --- local current_worktree_path = nil --- local on_change_callbacks = {} - ----@class GitWorktree +--- @class GitWorktree +--- @field config GitWorktreeConfig +--- @field _hooks GitWorktreeHooks local M = {} +M.__index = M ----@param opts? GitWorktree.Config -function M.setup(opts) - require('git-worktree.config').setup(opts) +function M:new() + local config = Config._get_defaults() + local obj = setmetatable({ + config = config, + _hooks = Hooks.hooks, + }, self) + return obj end -local function change_dirs(path) - local worktree_path = M.get_worktree_path(path) +local current = M:new() + +---@param self GitWorktree +--- @param opts table +function M.setup(self, opts) + if self ~= current then + self = current + end + self.config = Config.setup(opts) + return self +end + +local function get_absolute_path(path) + if Path:new(path):is_absolute() then + return path + else + return Path:new(vim.loop.cwd(), path):absolute() + end +end - local previous_worktree = Git.toplevel_dir() +local function change_dirs(path) + Log.info('changing dirs: %s ', path) + local worktree_path = get_absolute_path(path) + local previous_worktree = vim.loop.cwd() -- vim.loop.chdir(worktree_path) if Path:new(worktree_path):exists() then - local cmd = string.format('%s %s', Config.options.change_directory_command, worktree_path) - -- status:log().debug('Changing to directory ' .. worktree_path) + local cmd = string.format('%s %s', current.config.change_directory_command, worktree_path) + Log.debug('Changing to directory %s', worktree_path) vim.cmd(cmd) else - status:error('Could not chang to directory: ' .. worktree_path) + Log.error('Could not chang to directory: %s', worktree_path) end - if M._config.clearjumps_on_change then - -- status:log().debug('Clearing jumps') + if current.config.clearjumps_on_change then + Log.debug('Clearing jumps') vim.cmd('clearjumps') end return previous_worktree end +---@param hook GitWorkTreeHook +function M:hooks(hook) + self._hooks:add_listener(hook) +end + --Switch the current worktree ---@param path string -M.switch_worktree = function(path) - status:reset(2) - status:status(path) - +function M:switch_worktree(path) + -- status:reset(2) + -- status:status(path) + local cur_hooks = self._hooks Git.has_worktree(path, function(found) if not found then - status:error('worktree does not exists, please create it first ' .. path) + Log.error('worktree does not exists, please create it first %s ', path) end vim.schedule(function() - -- local prev_path = change_dirs(path) - change_dirs(path) - -- Hooks.emit_on_change(Enum.Operations.Switch, { path = path, prev_path = prev_path }) + local prev_path = change_dirs(path) + -- change_dirs(path) + Log.info('emiting hooks') + print(vim.inspect(current._hooks)) + cur_hooks:emit(Hooks.hook_event_names.SWITCH, path, prev_path) end) end) end @@ -310,9 +337,6 @@ end -- return true -- end -- --- M.on_tree_change = function(cb) --- table.insert(on_change_callbacks, cb) --- end -- -- M.reset = function() -- on_change_callbacks = {} @@ -326,13 +350,6 @@ end -- return current_worktree_path -- end -- --- M.get_worktree_path = function(path) --- if Path:new(path):is_absolute() then --- return path --- else --- return Path:new(git_worktree_root, path):absolute() --- end --- end -- -- M.setup = function(config) -- config = config or {} @@ -351,4 +368,4 @@ end -- M.setup() -- --M.Operations = Enum.Operations -return M +return current diff --git a/lua/git-worktree/logger.lua b/lua/git-worktree/logger.lua new file mode 100644 index 0000000..5e11aa5 --- /dev/null +++ b/lua/git-worktree/logger.lua @@ -0,0 +1,59 @@ +local LogLevels = { + TRACE = 0, + DEBUG = 1, + INFO = 2, + WARN = 3, + ERROR = 4, + OFF = 5, +} + +local LogHighlights = { + [1] = 'Comment', + [2] = 'None', + [3] = 'WarningMsg', + [4] = 'ErrorMsg', +} + +local M = {} + +--- @param level integer +--- @param msg string +local function log(level, msg) + local msg_lines = vim.split(msg, '\n', { plain = true }) + local msg_chunks = {} + for _, line in ipairs(msg_lines) do + table.insert(msg_chunks, { + string.format('[lsp-progress] %s\n', line), + LogHighlights[level], + }) + end + -- vim.api.nvim_echo(msg_chunks, false, {}) + vim.notify(msg, level) + print(msg) +end + +--- @param fmt string +--- @param ... any +M.debug = function(fmt, ...) + log(LogLevels.DEBUG, string.format(fmt, ...)) +end + +--- @param fmt string +--- @param ... any +M.info = function(fmt, ...) + log(LogLevels.INFO, string.format(fmt, ...)) +end + +--- @param fmt string +--- @param ... any +M.warn = function(fmt, ...) + log(LogLevels.WARN, string.format(fmt, ...)) +end + +--- @param fmt string +--- @param ... any +M.error = function(fmt, ...) + log(LogLevels.ERROR, string.format(fmt, ...)) +end + +return M diff --git a/lua/git-worktree/test/git_util.lua b/lua/git-worktree/test/git_util.lua index 1902b75..8b9ab28 100644 --- a/lua/git-worktree/test/git_util.lua +++ b/lua/git-worktree/test/git_util.lua @@ -1,5 +1,19 @@ local system = require('git-worktree.test.system_util') +-- local change_dir = function(dir) +-- vim.api.nvim_set_current_dir(dir) +-- end + +local create_worktree = function(folder_path, commitish) + system.run('git worktree add ' .. folder_path .. ' ' .. commitish) +end + +local project_dir = vim.api.nvim_exec('pwd', true) +local reset_cwd = function() + vim.cmd('cd ' .. project_dir) + vim.api.nvim_set_current_dir(project_dir) +end + local M = {} local origin_repo_path = nil @@ -50,13 +64,15 @@ function M.prepare_repo_bare() end function M.prepare_repo_worktree() + reset_cwd() M.setup_origin_repo() local working_dir = system.create_temp_dir('working-worktree-dir') vim.api.nvim_set_current_dir(working_dir) system.run(string.format('git clone --bare %s %s', origin_repo_path, working_dir)) - system.run('git worktree add wt master') - local worktree_dir = working_dir .. '/wt' + create_worktree('master', 'master') + create_worktree('featB', 'featB') + local worktree_dir = working_dir .. '/master' vim.api.nvim_set_current_dir(worktree_dir) return working_dir, worktree_dir end diff --git a/lua/git-worktree/worktree_spec.lua b/lua/git-worktree/worktree_spec.lua index b962804..489465a 100644 --- a/lua/git-worktree/worktree_spec.lua +++ b/lua/git-worktree/worktree_spec.lua @@ -1,3 +1,6 @@ +local git_harness = require('git-worktree.test.git_util') +local git_worktree = require('git-worktree') +local Path = require('plenary.path') -- local Status = require('git-worktree.status') -- local status = Status:new() @@ -5,50 +8,53 @@ -- luacheck: globals repo_dir describe('git-worktree', function() -- local completed_create = false - -- local completed_switch = false + local completed_switch = false -- local completed_delete = false - -- local reset_variables = function() - -- -- completed_create = false - -- completed_switch = false - -- -- completed_delete = false - -- end + local reset_variables = function() + -- completed_create = false + completed_switch = false + -- completed_delete = false + end - -- before_each(function() - -- reset_variables() - -- git_worktree.on_tree_change(function(op, _, _) - -- -- if op == git_worktree.Operations.Create then - -- -- completed_create = true - -- -- end - -- if op == git_worktree.Operations.Switch then - -- completed_switch = true - -- end - -- -- if op == git_worktree.Operations.Delete then - -- -- completed_delete = true - -- -- end - -- end) - -- end) + before_each(function() + reset_variables() + git_worktree = require('git-worktree') + git_worktree:hooks { + -- CREATE = function() + -- completed_create = true + -- end, + -- DELETE = function() + -- completed_delete = true + -- end, + SWITCH = function() + completed_switch = true + end, + } + end) - -- after_each(function() - -- -- git_worktree.reset() - -- end) + after_each(function() + -- git_worktree.reset() + end) + -- luacheck: globals repo_dir worktree_dir describe('Switch', function() describe('bare repo', function() - -- before_each(function() - -- repo_dir, worktree_dir = git_harness.prepare_repo_worktree() - -- end) + before_each(function() + repo_dir, worktree_dir = git_harness.prepare_repo_worktree() + end) it('from a bare repo with one worktree, able to switch to worktree (relative path)', function() - -- local path = 'master' - -- git_worktree.switch_worktree(path) + local wt = 'featB' + local path = '../' .. wt + git_worktree:switch_worktree(path) -- - -- vim.fn.wait(10000, function() - -- return completed_switch - -- end, 1000) + vim.fn.wait(10000, function() + return completed_switch + end, 1000) -- -- -- Check to make sure directory was switched - -- assert.are.same(vim.loop.cwd(), git_worktree:get_root() .. Path.path.sep .. path) - assert.are.same(vim.loop.cwd(), vim.loop.cwd()) + assert.is_true(completed_switch) + assert.are.same(vim.loop.cwd(), repo_dir .. Path.path.sep .. wt) end) end) end) From da59fb3d4df6f587579677bdb5b6e4edc059c82d Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Fri, 29 Dec 2023 15:22:07 -0500 Subject: [PATCH 16/33] ci: add test for switching normal repo --- lua/git-worktree/git.lua | 4 +-- lua/git-worktree/git_spec.lua | 24 ++++++------- lua/git-worktree/test/git_util.lua | 57 ++++++++++++++++++++---------- lua/git-worktree/worktree_spec.lua | 27 ++++++++++++-- 4 files changed, 75 insertions(+), 37 deletions(-) diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index f197608..cd56186 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -15,7 +15,6 @@ local M = {} function M.has_worktree(path_str, cb) local found = false local path = Path:new(path_str) - local git_worktree_root = M.gitroot_dir() if path_str == '.' then path_str = vim.loop.cwd() @@ -38,8 +37,7 @@ function M.has_worktree(path_str, cb) if path:is_absolute() then start = data == path_str else - local worktree_path = - Path:new(string.format('%s' .. Path.path.sep .. '%s', git_worktree_root, path_str)) + local worktree_path = Path:new(string.format('%s' .. Path.path.sep .. '%s', vim.loop.cwd(), path_str)) worktree_path = worktree_path:absolute() start = data == worktree_path end diff --git a/lua/git-worktree/git_spec.lua b/lua/git-worktree/git_spec.lua index 1e1ec0a..97862dc 100644 --- a/lua/git-worktree/git_spec.lua +++ b/lua/git-worktree/git_spec.lua @@ -15,11 +15,11 @@ local status = Status:new() local cwd = vim.fn.getcwd() --- luacheck: globals repo_dir worktree_dir +-- luacheck: globals working_dir master_dir describe('git-worktree git operations', function() describe('in normal repo', function() before_each(function() - repo_dir = git_harness.prepare_repo() + working_dir, master_dir = git_harness.prepare_repo() status:reset(0) end) after_each(function() @@ -27,18 +27,18 @@ describe('git-worktree git operations', function() end) it('finds toplevel.', function() local ret = gwt_git.toplevel_dir() - assert.are.same(ret, repo_dir) + assert.are.same(ret, master_dir) end) it('finds root git dir.', function() local ret = gwt_git.gitroot_dir() - local root_repo_dir = repo_dir .. '/.git' + local root_repo_dir = master_dir .. '/.git' assert.are.same(ret, root_repo_dir) end) it('has_worktree valid absolute.', function() local completed = false local ret = false - gwt_git.has_worktree(repo_dir, function(found) + gwt_git.has_worktree(master_dir, function(found) completed = true ret = found end) @@ -53,7 +53,7 @@ describe('git-worktree git operations', function() local completed = false local ret = false - gwt_git.has_worktree('..', function(found) + gwt_git.has_worktree('.', function(found) completed = true ret = found end) @@ -98,7 +98,7 @@ describe('git-worktree git operations', function() describe('in bare repo', function() before_each(function() - repo_dir = git_harness.prepare_repo_bare() + working_dir = git_harness.prepare_repo_bare() status:reset(0) end) after_each(function() @@ -110,13 +110,13 @@ describe('git-worktree git operations', function() end) it('finds root git dir.', function() local ret_git_dir = gwt_git.gitroot_dir() - assert.are.same(ret_git_dir, repo_dir) + assert.are.same(ret_git_dir, working_dir) end) it('has_worktree valid absolute.', function() local completed = false local ret = false - gwt_git.has_worktree(repo_dir, function(found) + gwt_git.has_worktree(working_dir, function(found) completed = true ret = found end) @@ -176,7 +176,7 @@ describe('git-worktree git operations', function() describe('in worktree repo', function() before_each(function() - repo_dir, worktree_dir = git_harness.prepare_repo_worktree() + working_dir, master_dir = git_harness.prepare_repo_bare_worktree(1) status:reset(0) end) after_each(function() @@ -184,11 +184,11 @@ describe('git-worktree git operations', function() end) it('finds toplevel.', function() local ret = gwt_git.toplevel_dir() - assert.are.same(ret, worktree_dir) + assert.are.same(ret, master_dir) end) it('finds root git dir.', function() local ret = gwt_git.gitroot_dir() - assert.are.same(ret, repo_dir) + assert.are.same(ret, working_dir) end) end) end) diff --git a/lua/git-worktree/test/git_util.lua b/lua/git-worktree/test/git_util.lua index 8b9ab28..82bcf10 100644 --- a/lua/git-worktree/test/git_util.lua +++ b/lua/git-worktree/test/git_util.lua @@ -8,12 +8,6 @@ local create_worktree = function(folder_path, commitish) system.run('git worktree add ' .. folder_path .. ' ' .. commitish) end -local project_dir = vim.api.nvim_exec('pwd', true) -local reset_cwd = function() - vim.cmd('cd ' .. project_dir) - vim.api.nvim_set_current_dir(project_dir) -end - local M = {} local origin_repo_path = nil @@ -44,14 +38,16 @@ function M.prepare_repo() M.setup_origin_repo() local working_dir = system.create_temp_dir('working-dir') + local master_dir = working_dir .. '/master' vim.api.nvim_set_current_dir(working_dir) - system.run(string.format('git clone %s %s', origin_repo_path, working_dir)) + system.run(string.format('git clone %s %s', origin_repo_path, master_dir)) + vim.api.nvim_set_current_dir(master_dir) system.run([[ git config remote.origin.url git@github.com:test/test.git git config user.email "test@test.test" git config user.name "Test User" ]]) - return working_dir + return working_dir, master_dir end function M.prepare_repo_bare() @@ -63,18 +59,41 @@ function M.prepare_repo_bare() return working_dir end -function M.prepare_repo_worktree() - reset_cwd() - M.setup_origin_repo() +--- @param num_worktrees integer +function M.prepare_repo_bare_worktree(num_worktrees) + local working_dir = M.prepare_repo_bare() + local master_dir = working_dir .. '/master' - local working_dir = system.create_temp_dir('working-worktree-dir') - vim.api.nvim_set_current_dir(working_dir) - system.run(string.format('git clone --bare %s %s', origin_repo_path, working_dir)) - create_worktree('master', 'master') - create_worktree('featB', 'featB') - local worktree_dir = working_dir .. '/master' - vim.api.nvim_set_current_dir(worktree_dir) - return working_dir, worktree_dir + if num_worktrees > 0 then + create_worktree('master', 'master') + end + + if num_worktrees > 1 then + create_worktree('featB', 'featB') + end + + if num_worktrees > 2 then + create_worktree('featC', 'featC') + end + + vim.api.nvim_set_current_dir(master_dir) + + return working_dir, master_dir +end + +--- @param num_worktrees integer +function M.prepare_repo_normal_worktree(num_worktrees) + local working_dir, master_dir = M.prepare_repo() + + if num_worktrees > 0 then + create_worktree('../featB', 'featB') + end + + if num_worktrees > 1 then + create_worktree('../featC', 'featC') + end + + return working_dir, master_dir end return M diff --git a/lua/git-worktree/worktree_spec.lua b/lua/git-worktree/worktree_spec.lua index 489465a..84f7963 100644 --- a/lua/git-worktree/worktree_spec.lua +++ b/lua/git-worktree/worktree_spec.lua @@ -5,6 +5,8 @@ local Path = require('plenary.path') -- local status = Status:new() +local cwd = vim.fn.getcwd() + -- luacheck: globals repo_dir describe('git-worktree', function() -- local completed_create = false @@ -35,13 +37,14 @@ describe('git-worktree', function() after_each(function() -- git_worktree.reset() + vim.api.nvim_command('cd ' .. cwd) end) - -- luacheck: globals repo_dir worktree_dir + -- luacheck: globals working_dir master_dir describe('Switch', function() describe('bare repo', function() before_each(function() - repo_dir, worktree_dir = git_harness.prepare_repo_worktree() + working_dir, master_dir = git_harness.prepare_repo_bare_worktree(2) end) it('from a bare repo with one worktree, able to switch to worktree (relative path)', function() local wt = 'featB' @@ -54,7 +57,25 @@ describe('git-worktree', function() -- -- -- Check to make sure directory was switched assert.is_true(completed_switch) - assert.are.same(vim.loop.cwd(), repo_dir .. Path.path.sep .. wt) + assert.are.same(vim.loop.cwd(), working_dir .. Path.path.sep .. wt) + end) + end) + describe('normal repo', function() + before_each(function() + working_dir, master_dir = git_harness.prepare_repo_normal_worktree(1) + end) + it('from a normal repo with one worktree, able to switch to worktree (relative path)', function() + local wt = 'featB' + local path = '../' .. wt + git_worktree:switch_worktree(path) + -- + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + -- + -- -- Check to make sure directory was switched + assert.is_true(completed_switch) + assert.are.same(vim.loop.cwd(), working_dir .. Path.path.sep .. wt) end) end) end) From 79f9f82dec663fcc1c2e570274dfc928e9f07630 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Fri, 29 Dec 2023 21:59:04 -0500 Subject: [PATCH 17/33] refactor: create worktree --- lua/git-worktree/git.lua | 161 ++++++++++++------ lua/git-worktree/hooks.lua | 1 + lua/git-worktree/init.lua | 261 ++--------------------------- lua/git-worktree/worktree.lua | 162 ++++++++++++++++++ lua/git-worktree/worktree_spec.lua | 70 ++++++-- 5 files changed, 346 insertions(+), 309 deletions(-) create mode 100644 lua/git-worktree/worktree.lua diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index cd56186..226baa0 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -1,9 +1,7 @@ -local Job = require('plenary').job +local Job = require('plenary.job') local Path = require('plenary.path') --- local Status = require('git-worktree.status') --- --- local status = Status:new() --- +local Log = require('git-worktree.logger') + ---@class GitWorktreeGitOps local M = {} @@ -53,8 +51,7 @@ function M.has_worktree(path_str, cb) cb(found) end) - -- TODO: I really don't want status's spread everywhere... seems bad - --status:next_status('Checking for worktree ' .. path) + Log.debug('Checking for worktree %s', path) job:start() end @@ -134,7 +131,6 @@ function M.gitroot_dir() return table.concat(stdout, '') end --- @param is_worktree boolean --- @return string|nil function M.toplevel_dir() local job = Job:new { @@ -163,44 +159,25 @@ function M.toplevel_dir() return table.concat(stdout, '') end --- --- @return string|nil --- function M.find_git_toplevel() --- local find_toplevel_job = Job:new({ --- "git", --- "rev-parse", --- "--show-toplevel", --- cwd = vim.loop.cwd(), --- }) --- local stdout, code = find_toplevel_job:sync() --- if code == 0 then --- stdout = table.concat(stdout, "") --- return stdout --- else --- return nil --- end --- end --- --- function M.has_branch(branch, cb) --- local found = false --- local job = Job:new({ --- "git", --- "branch", --- on_stdout = function(_, data) --- -- remove markere on current branch --- data = data:gsub("*", "") --- data = vim.trim(data) --- found = found or data == branch --- end, --- cwd = vim.loop.cwd(), --- }) --- --- -- TODO: I really don't want status's spread everywhere... seems bad --- status:next_status(string.format("Checking for branch %s", branch)) --- job:after(function() --- status:status("found branch: " .. tostring(found)) --- cb(found) --- end):start() --- end +function M.has_branch(branch, cb) + local found = false + local job = Job:new { + 'git', + 'branch', + on_stdout = function(_, data) + -- remove markere on current branch + data = data:gsub('*', '') + data = vim.trim(data) + found = found or data == branch + end, + cwd = vim.loop.cwd(), + } + + -- TODO: I really don't want status's spread everywhere... seems bad + job:after(function() + cb(found) + end):start() +end -- -- function M.has_origin() -- local found = false @@ -222,5 +199,95 @@ end -- -- return found -- end --- + +--- @param path string +--- @param branch string +--- @param found_branch boolean +--- @return Job +function M.create_worktree_job(path, branch, found_branch) + local worktree_add_cmd = 'git' + local worktree_add_args = { 'worktree', 'add' } + + if not found_branch then + table.insert(worktree_add_args, '-b') + table.insert(worktree_add_args, branch) + table.insert(worktree_add_args, path) + else + table.insert(worktree_add_args, path) + table.insert(worktree_add_args, branch) + end + + return Job:new { + command = worktree_add_cmd, + args = worktree_add_args, + cwd = vim.loop.cwd(), + on_start = function() + Log.debug(worktree_add_cmd .. ' ' .. table.concat(worktree_add_args, ' ')) + end, + } +end + +--- @param path string +--- @return plenary:Job +function M.fetchall_job(path) + return Job:new { + 'git', + 'fetch', + '--all', + cwd = path, + on_start = function() + Log.debug('git fetch --all (This may take a moment)') + end, + } +end + +--- @param path string +--- @param branch string +--- @param upstream string +--- @return plenary:Job +function M.setbranch_job(path, branch, upstream) + local set_branch_cmd = 'git' + local set_branch_args = { 'branch', string.format('--set-upstream-to=%s/%s', upstream, branch) } + return Job:new { + command = set_branch_cmd, + args = set_branch_args, + cwd = path, + on_start = function() + Log.debug(set_branch_cmd .. ' ' .. table.concat(set_branch_args, ' ')) + end, + } +end + +--- @param path string +--- @param branch string +--- @param upstream string +--- @return plenary:Job +function M.setpush_job(path, branch, upstream) + -- TODO: How to configure origin??? Should upstream ever be the push + -- destination? + local set_push_cmd = 'git' + local set_push_args = { 'push', '--set-upstream', upstream, branch, path } + return Job:new { + command = set_push_cmd, + args = set_push_args, + cwd = path, + on_start = function() + Log.debug(set_push_cmd .. ' ' .. table.concat(set_push_args, ' ')) + end, + } +end + +--- @param path string +--- @return plenary:Job +function M.rebase_job(path) + return Job:new { + 'git', + 'rebase', + cwd = path, + on_start = function() + Log.debug('git rebase') + end, + } +end + return M diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 80624e9..86ac37e 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -42,6 +42,7 @@ local M = {} M.hooks = GitWorktreeHooks:new() M.hook_event_names = { + CREATE = 'CREATE', SWITCH = 'SWITCH', } diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index ae1d296..a44955a 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -1,9 +1,6 @@ -local Path = require('plenary.path') - local Config = require('git-worktree.config') -local Git = require('git-worktree.git') local Hooks = require('git-worktree.hooks') -local Log = require('git-worktree.logger') +local Worktree = require('git-worktree.worktree') --- @class GitWorktree --- @field config GitWorktreeConfig @@ -33,36 +30,6 @@ function M.setup(self, opts) return self end -local function get_absolute_path(path) - if Path:new(path):is_absolute() then - return path - else - return Path:new(vim.loop.cwd(), path):absolute() - end -end - -local function change_dirs(path) - Log.info('changing dirs: %s ', path) - local worktree_path = get_absolute_path(path) - local previous_worktree = vim.loop.cwd() - - -- vim.loop.chdir(worktree_path) - if Path:new(worktree_path):exists() then - local cmd = string.format('%s %s', current.config.change_directory_command, worktree_path) - Log.debug('Changing to directory %s', worktree_path) - vim.cmd(cmd) - else - Log.error('Could not chang to directory: %s', worktree_path) - end - - if current.config.clearjumps_on_change then - Log.debug('Clearing jumps') - vim.cmd('clearjumps') - end - - return previous_worktree -end - ---@param hook GitWorkTreeHook function M:hooks(hook) self._hooks:add_listener(hook) @@ -70,184 +37,19 @@ end --Switch the current worktree ---@param path string +-- luacheck:ignore self function M:switch_worktree(path) - -- status:reset(2) - -- status:status(path) - local cur_hooks = self._hooks - Git.has_worktree(path, function(found) - if not found then - Log.error('worktree does not exists, please create it first %s ', path) - end + Worktree.switch(path) +end - vim.schedule(function() - local prev_path = change_dirs(path) - -- change_dirs(path) - Log.info('emiting hooks') - print(vim.inspect(current._hooks)) - cur_hooks:emit(Hooks.hook_event_names.SWITCH, path, prev_path) - end) - end) +--Create a worktree +---@param path string +---@param branch string +---@param upstream? string +-- luacheck:ignore self +function M:create_worktree(path, branch, upstream) + Worktree.create(path, branch, upstream) end --- --- local function create_worktree_job(path, branch, found_branch) --- local worktree_add_cmd = "git" --- local worktree_add_args = { "worktree", "add" } --- --- if not found_branch then --- table.insert(worktree_add_args, "-b") --- table.insert(worktree_add_args, branch) --- table.insert(worktree_add_args, path) --- else --- table.insert(worktree_add_args, path) --- table.insert(worktree_add_args, branch) --- end --- --- return Job:new({ --- command = worktree_add_cmd, --- args = worktree_add_args, --- cwd = git_worktree_root, --- on_start = function() --- status:next_status(worktree_add_cmd .. " " .. table.concat(worktree_add_args, " ")) --- end, --- }) --- end --- --- --- local function failure(from, cmd, path, soft_error) --- return function(e) --- local error_message = string.format( --- "%s Failed: PATH %s CMD %s RES %s, ERR %s", --- from, --- path, --- vim.inspect(cmd), --- vim.inspect(e:result()), --- vim.inspect(e:stderr_result()) --- ) --- --- if soft_error then --- status:status(error_message) --- else --- status:error(error_message) --- end --- end --- end --- --- local function create_worktree(path, branch, upstream, found_branch) --- local create = create_worktree_job(path, branch, found_branch) --- --- local worktree_path --- if Path:new(path):is_absolute() then --- worktree_path = path --- else --- worktree_path = Path:new(git_worktree_root, path):absolute() --- end --- --- local fetch = Job:new({ --- "git", --- "fetch", --- "--all", --- cwd = worktree_path, --- on_start = function() --- status:next_status("git fetch --all (This may take a moment)") --- end, --- }) --- --- local set_branch_cmd = "git" --- local set_branch_args = { "branch", string.format("--set-upstream-to=%s/%s", upstream, branch) } --- local set_branch = Job:new({ --- command = set_branch_cmd, --- args = set_branch_args, --- cwd = worktree_path, --- on_start = function() --- status:next_status(set_branch_cmd .. " " .. table.concat(set_branch_args, " ")) --- end, --- }) --- --- -- TODO: How to configure origin??? Should upstream ever be the push --- -- destination? --- local set_push_cmd = "git" --- local set_push_args = { "push", "--set-upstream", upstream, branch, path } --- local set_push = Job:new({ --- command = set_push_cmd, --- args = set_push_args, --- cwd = worktree_path, --- on_start = function() --- status:next_status(set_push_cmd .. " " .. table.concat(set_push_args, " ")) --- end, --- }) --- --- local rebase = Job:new({ --- "git", --- "rebase", --- cwd = worktree_path, --- on_start = function() --- status:next_status("git rebase") --- end, --- }) --- --- if upstream ~= nil then --- create:and_then_on_success(fetch) --- fetch:and_then_on_success(set_branch) --- --- if M._config.autopush then --- -- These are "optional" operations. --- -- We have to figure out how we want to handle these... --- set_branch:and_then(set_push) --- set_push:and_then(rebase) --- set_push:after_failure(failure("create_worktree", set_branch.args, worktree_path, true)) --- else --- set_branch:and_then(rebase) --- end --- --- create:after_failure(failure("create_worktree", create.args, git_worktree_root)) --- fetch:after_failure(failure("create_worktree", fetch.args, worktree_path)) --- --- set_branch:after_failure(failure("create_worktree", set_branch.args, worktree_path, true)) --- --- rebase:after(function() --- if rebase.code ~= 0 then --- status:status("Rebase failed, but that's ok.") --- end --- --- vim.schedule(function() --- Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) --- M.switch_worktree(path) --- end) --- end) --- else --- create:after(function() --- vim.schedule(function() --- Hooks.emit_on_change(Enum.Operations.Create, { path = path, branch = branch, upstream = upstream }) --- M.switch_worktree(path) --- end) --- end) --- end --- --- create:start() --- end --- --- M.create_worktree = function(path, branch, upstream) --- status:reset(8) --- --- if upstream == nil then --- if Git.has_origin() then --- upstream = "origin" --- end --- end --- --- M.setup_git_info() --- --- has_worktree(path, function(found) --- if found then --- status:error("worktree already exists") --- end --- --- Git.has_branch(branch, function(found_branch) --- create_worktree(path, branch, upstream, found_branch) --- end) --- end) --- end --- -- -- M.delete_worktree = function(path, force, opts) @@ -293,15 +95,7 @@ end -- delete:start() -- end) -- end --- --- M.set_worktree_root = function(wd) --- git_worktree_root = wd --- end --- --- M.set_current_worktree_path = function(wd) --- current_worktree_path = wd --- end --- + -- M.update_current_buffer = function(prev_path) -- if prev_path == nil then -- return false @@ -336,36 +130,5 @@ end -- vim.api.nvim_set_current_buf(bufnr) -- return true -- end --- --- --- M.reset = function() --- on_change_callbacks = {} --- end --- --- M.get_root = function() --- return git_worktree_root --- end --- --- M.get_current_worktree_path = function() --- return current_worktree_path --- end --- --- --- M.setup = function(config) --- config = config or {} --- M._config = vim.tbl_deep_extend("force", { --- change_directory_command = "cd", --- update_on_change = true, --- update_on_change_command = "e .", --- clearjumps_on_change = true, --- -- default to false to avoid breaking the previous default behavior --- confirm_telescope_deletions = false, --- -- should this default to true or false? --- autopush = false, --- }, config) --- end --- --- M.setup() --- --M.Operations = Enum.Operations return current diff --git a/lua/git-worktree/worktree.lua b/lua/git-worktree/worktree.lua new file mode 100644 index 0000000..38fe138 --- /dev/null +++ b/lua/git-worktree/worktree.lua @@ -0,0 +1,162 @@ +local Path = require('plenary.path') + +local Hooks = require('git-worktree.hooks') +local Git = require('git-worktree.git') +local Log = require('git-worktree.logger') + +local function get_absolute_path(path) + if Path:new(path):is_absolute() then + return path + else + return Path:new(vim.loop.cwd(), path):absolute() + end +end + +local function change_dirs(path) + local Gwt = require('git-worktree') + Log.info('changing dirs: %s ', path) + local worktree_path = get_absolute_path(path) + local previous_worktree = vim.loop.cwd() + + -- vim.loop.chdir(worktree_path) + print(vim.inspect(Gwt)) + if Path:new(worktree_path):exists() then + local cmd = string.format('%s %s', Gwt.config.change_directory_command, worktree_path) + Log.debug('Changing to directory %s', worktree_path) + vim.cmd(cmd) + else + Log.error('Could not chang to directory: %s', worktree_path) + end + + if Gwt.config.clearjumps_on_change then + Log.debug('Clearing jumps') + vim.cmd('clearjumps') + end + + return previous_worktree +end + +local M = {} + +--- SWITCH --- + +--Switch the current worktree +---@param path string +function M.switch(path) + local Gwt = require('git-worktree') + local cur_hooks = Gwt._hooks + Git.has_worktree(path, function(found) + Log.debug('test') + if not found then + Log.error('worktree does not exists, please create it first %s ', path) + end + Log.debug('has worktree') + + vim.schedule(function() + local prev_path = change_dirs(path) + cur_hooks:emit(Hooks.hook_event_names.SWITCH, path, prev_path) + end) + end) +end + +--- CREATE --- + +local function create_failure(from, cmd, path, soft_error) + return function(e) + local error_message = string.format( + '%s Failed: PATH %s CMD %s RES %s, ERR %s', + from, + path, + vim.inspect(cmd), + vim.inspect(e:result()), + vim.inspect(e:stderr_result()) + ) + + if soft_error then + Log.error(error_message) + else + Log.error(error_message) + end + end +end + +--crerate a worktree +---@param path string +---@param branch string +---@param upstream? string +function M.create(path, branch, upstream) + -- if upstream == nil then + -- if Git.has_origin() then + -- upstream = 'origin' + -- end + -- end + + -- M.setup_git_info() + + Git.has_worktree(path, function(found) + if found then + Log.error('worktree already exists') + return + end + + Git.has_branch(branch, function(found_branch) + local worktree_path + if Path:new(path):is_absolute() then + worktree_path = path + else + worktree_path = Path:new(vim.loop.cwd(), path):absolute() + end + + -- create_worktree(path, branch, upstream, found_branch) + local create_wt_job = Git.create_worktree_job(path, branch, found_branch) + + local Gwt = require('git-worktree') + local cur_hooks = Gwt._hooks + + if upstream ~= nil then + local fetch = Git.fetchall_job(path, branch, upstream) + local set_branch = Git.setbranch_job(path, branch, upstream) + local set_push = Git.setpush_job(path, branch, upstream) + local rebase = Git.rebase_job(path) + + create_wt_job:and_then_on_success(fetch) + fetch:and_then_on_success(set_branch) + + if Gwt.config.autopush then + -- These are "optional" operations. + -- We have to figure out how we want to handle these... + set_branch:and_then(set_push) + set_push:and_then(rebase) + set_push:after_failure(create_failure('create_worktree', set_branch.args, worktree_path, true)) + else + set_branch:and_then(rebase) + end + + create_wt_job:after_failure(create_failure('create_worktree', create_wt_job.args, vim.loop.cwd())) + fetch:after_failure(create_failure('create_worktree', fetch.args, worktree_path)) + + set_branch:after_failure(create_failure('create_worktree', set_branch.args, worktree_path, true)) + + rebase:after(function() + if rebase.code ~= 0 then + Log.devel("Rebase failed, but that's ok.") + end + + vim.schedule(function() + cur_hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) + M.switch(path) + end) + end) + else + create_wt_job:after(function() + vim.schedule(function() + cur_hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) + M.switch(path) + end) + end) + end + create_wt_job:start() + end) + end) +end +return M diff --git a/lua/git-worktree/worktree_spec.lua b/lua/git-worktree/worktree_spec.lua index 84f7963..675c838 100644 --- a/lua/git-worktree/worktree_spec.lua +++ b/lua/git-worktree/worktree_spec.lua @@ -8,13 +8,13 @@ local Path = require('plenary.path') local cwd = vim.fn.getcwd() -- luacheck: globals repo_dir -describe('git-worktree', function() - -- local completed_create = false +describe('[Worktree]', function() + local completed_create = false local completed_switch = false -- local completed_delete = false local reset_variables = function() - -- completed_create = false + completed_create = false completed_switch = false -- completed_delete = false end @@ -22,10 +22,12 @@ describe('git-worktree', function() before_each(function() reset_variables() git_worktree = require('git-worktree') + git_worktree:setup {} git_worktree:hooks { - -- CREATE = function() - -- completed_create = true - -- end, + CREATE = function() + print('called create') + completed_create = true + end, -- DELETE = function() -- completed_delete = true -- end, @@ -41,12 +43,12 @@ describe('git-worktree', function() end) -- luacheck: globals working_dir master_dir - describe('Switch', function() - describe('bare repo', function() + describe('[Switch]', function() + describe('[bare repo]', function() before_each(function() working_dir, master_dir = git_harness.prepare_repo_bare_worktree(2) end) - it('from a bare repo with one worktree, able to switch to worktree (relative path)', function() + it('able to switch to worktree (relative path)', function() local wt = 'featB' local path = '../' .. wt git_worktree:switch_worktree(path) @@ -57,14 +59,14 @@ describe('git-worktree', function() -- -- -- Check to make sure directory was switched assert.is_true(completed_switch) - assert.are.same(vim.loop.cwd(), working_dir .. Path.path.sep .. wt) + assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) end) end) - describe('normal repo', function() + describe('[normal repo]', function() before_each(function() working_dir, master_dir = git_harness.prepare_repo_normal_worktree(1) end) - it('from a normal repo with one worktree, able to switch to worktree (relative path)', function() + it('able to switch to worktree (relative path)', function() local wt = 'featB' local path = '../' .. wt git_worktree:switch_worktree(path) @@ -75,7 +77,49 @@ describe('git-worktree', function() -- -- -- Check to make sure directory was switched assert.is_true(completed_switch) - assert.are.same(vim.loop.cwd(), working_dir .. Path.path.sep .. wt) + assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) + end) + end) + end) + -- luacheck: globals working_dir master_dir + describe('[CREATE]', function() + describe('[bare repo]', function() + before_each(function() + working_dir, master_dir = git_harness.prepare_repo_bare_worktree(1) + end) + it('able to create a worktree (relative path)', function() + local wt = 'featB' + local path = '../' .. wt + git_worktree:create_worktree(path, wt) + -- + vim.fn.wait(10000, function() + -- need to wait for final switch + return completed_switch + end, 1000) + -- + -- -- Check to make sure directory was switched + assert.is_true(completed_create) + assert.is_true(completed_switch) + assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) + end) + end) + describe('[normal repo]', function() + before_each(function() + working_dir, master_dir = git_harness.prepare_repo_normal_worktree(0) + end) + it('able to create a worktree (relative path)', function() + local wt = 'featB' + local path = '../' .. wt + git_worktree:create_worktree(path, wt) + -- + vim.fn.wait(10000, function() + return completed_switch + end, 1000) + -- + -- -- Check to make sure directory was switched + assert.is_true(completed_create) + assert.is_true(completed_switch) + assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) end) end) end) From fc3c4f22138d83077d05837818882ae73e120126 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Sat, 30 Dec 2023 12:55:23 -0500 Subject: [PATCH 18/33] refactor: delete worktree --- lua/git-worktree/git.lua | 23 ++++++++ lua/git-worktree/hooks.lua | 1 + lua/git-worktree/init.lua | 88 +++------------------------- lua/git-worktree/worktree.lua | 92 ++++++++++++++++++++++-------- lua/git-worktree/worktree_spec.lua | 63 +++++++++++++++++--- 5 files changed, 155 insertions(+), 112 deletions(-) diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index 226baa0..1c94fdb 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -43,11 +43,13 @@ function M.has_worktree(path_str, cb) -- TODO: This is clearly a hack (do not think we need this anymore?) --local start_with_head = string.find(data, string.format('[heads/%s]', path), 1, true) found = found or start + Log.debug('found: %s', found) end, cwd = vim.loop.cwd(), } job:after(function() + Log.debug('calling after') cb(found) end) @@ -227,6 +229,27 @@ function M.create_worktree_job(path, branch, found_branch) } end +--- @param path string +--- @param force boolean +--- @return Job +function M.delete_worktree_job(path, force) + local worktree_del_cmd = 'git' + local worktree_del_args = { 'worktree', 'remove', path } + + if force then + table.insert(worktree_del_args, '--force') + end + + return Job:new { + command = worktree_del_cmd, + args = worktree_del_args, + cwd = vim.loop.cwd(), + on_start = function() + Log.debug(worktree_del_cmd .. ' ' .. table.concat(worktree_del_args, ' ')) + end, + } +end + --- @param path string --- @return plenary:Job function M.fetchall_job(path) diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 86ac37e..8cfae90 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -43,6 +43,7 @@ M.hooks = GitWorktreeHooks:new() M.hook_event_names = { CREATE = 'CREATE', + DELETE = 'DELETE', SWITCH = 'SWITCH', } diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index a44955a..e0136d3 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -42,7 +42,7 @@ function M:switch_worktree(path) Worktree.switch(path) end ---Create a worktree +--Create a worktree ---@param path string ---@param branch string ---@param upstream? string @@ -51,84 +51,12 @@ function M:create_worktree(path, branch, upstream) Worktree.create(path, branch, upstream) end --- --- M.delete_worktree = function(path, force, opts) --- if not opts then --- opts = {} --- end --- --- status:reset(2) --- M.setup_git_info() --- has_worktree(path, function(found) --- if not found then --- status:error(string.format("Worktree %s does not exist", path)) --- end --- --- local cmd = { --- "git", --- "worktree", --- "remove", --- path, --- } --- --- if force then --- table.insert(cmd, "--force") --- end --- --- local delete = Job:new(cmd) --- delete:after_success(vim.schedule_wrap(function() --- Hooks.emit_on_change(Enum.Operations.Delete, { path = path }) --- if opts.on_success then --- opts.on_success() --- end --- end)) --- --- delete:after_failure(function(e) --- -- callback has to be called before failure() because failure() --- -- halts code execution --- if opts.on_failure then --- opts.on_failure(e) --- end --- --- failure(cmd, vim.loop.cwd())(e) --- end) --- delete:start() --- end) --- end - --- M.update_current_buffer = function(prev_path) --- if prev_path == nil then --- return false --- end --- --- local cwd = vim.loop.cwd() --- local current_buf_name = vim.api.nvim_buf_get_name(0) --- if not current_buf_name or current_buf_name == "" then --- return false --- end --- --- local name = Path:new(current_buf_name):absolute() --- local start1, _ = string.find(name, cwd .. Path.path.sep, 1, true) --- if start1 ~= nil then --- return true --- end --- --- local start, fin = string.find(name, prev_path, 1, true) --- if start == nil then --- return false --- end --- --- local local_name = name:sub(fin + 2) --- --- local final_path = Path:new({ cwd, local_name }):absolute() --- --- if not Path:new(final_path):exists() then --- return false --- end --- --- local bufnr = vim.fn.bufnr(final_path, true) --- vim.api.nvim_set_current_buf(bufnr) --- return true --- end +--Delete a worktree +---@param path string +---@param force boolean +---@param opts any +function M:delete_worktree(path, force, opts) + Worktree.delete(path, force, opts) +end return current diff --git a/lua/git-worktree/worktree.lua b/lua/git-worktree/worktree.lua index 38fe138..d51c7bc 100644 --- a/lua/git-worktree/worktree.lua +++ b/lua/git-worktree/worktree.lua @@ -36,6 +36,25 @@ local function change_dirs(path) return previous_worktree end +local function failure(from, cmd, path, soft_error) + return function(e) + local error_message = string.format( + '%s Failed: PATH %s CMD %s RES %s, ERR %s', + from, + path, + vim.inspect(cmd), + vim.inspect(e:result()), + vim.inspect(e:stderr_result()) + ) + + if soft_error then + Log.error(error_message) + else + Log.error(error_message) + end + end +end + local M = {} --- SWITCH --- @@ -61,25 +80,6 @@ end --- CREATE --- -local function create_failure(from, cmd, path, soft_error) - return function(e) - local error_message = string.format( - '%s Failed: PATH %s CMD %s RES %s, ERR %s', - from, - path, - vim.inspect(cmd), - vim.inspect(e:result()), - vim.inspect(e:stderr_result()) - ) - - if soft_error then - Log.error(error_message) - else - Log.error(error_message) - end - end -end - --crerate a worktree ---@param path string ---@param branch string @@ -127,15 +127,15 @@ function M.create(path, branch, upstream) -- We have to figure out how we want to handle these... set_branch:and_then(set_push) set_push:and_then(rebase) - set_push:after_failure(create_failure('create_worktree', set_branch.args, worktree_path, true)) + set_push:after_failure(failure('create_worktree', set_branch.args, worktree_path, true)) else set_branch:and_then(rebase) end - create_wt_job:after_failure(create_failure('create_worktree', create_wt_job.args, vim.loop.cwd())) - fetch:after_failure(create_failure('create_worktree', fetch.args, worktree_path)) + create_wt_job:after_failure(failure('create_worktree', create_wt_job.args, vim.loop.cwd())) + fetch:after_failure(failure('create_worktree', fetch.args, worktree_path)) - set_branch:after_failure(create_failure('create_worktree', set_branch.args, worktree_path, true)) + set_branch:after_failure(failure('create_worktree', set_branch.args, worktree_path, true)) rebase:after(function() if rebase.code ~= 0 then @@ -159,4 +159,50 @@ function M.create(path, branch, upstream) end) end) end + +--- DELETE --- + +--Delete a worktree +---@param path string +---@param force boolean +---@param opts any +function M.delete(path, force, opts) + if not opts then + opts = {} + end + + Git.has_worktree(path, function(found) + Log.info('OMG here') + if not found then + Log.error('Worktree %s does not exist', path) + else + Log.info('Worktree %s does exist', path) + end + local Gwt = require('git-worktree') + local cur_hooks = Gwt._hooks + + local delete = Git.delete_worktree_job(path, force) + delete:after_success(vim.schedule_wrap(function() + Log.info('delete after success') + cur_hooks:emit(Hooks.hook_event_names.DELETE, path) + if opts.on_success then + opts.on_success() + end + end)) + + delete:after_failure(function(e) + Log.info('delete after failure') + -- callback has to be called before failure() because failure() + -- halts code execution + if opts.on_failure then + opts.on_failure(e) + end + + failure(delete.cmd, vim.loop.cwd())(e) + end) + Log.info('delete start job') + delete:start() + end) +end + return M diff --git a/lua/git-worktree/worktree_spec.lua b/lua/git-worktree/worktree_spec.lua index 675c838..93dac07 100644 --- a/lua/git-worktree/worktree_spec.lua +++ b/lua/git-worktree/worktree_spec.lua @@ -1,5 +1,6 @@ local git_harness = require('git-worktree.test.git_util') local git_worktree = require('git-worktree') +local Log = require('git-worktree.logger') local Path = require('plenary.path') -- local Status = require('git-worktree.status') @@ -11,12 +12,12 @@ local cwd = vim.fn.getcwd() describe('[Worktree]', function() local completed_create = false local completed_switch = false - -- local completed_delete = false + local completed_delete = false local reset_variables = function() completed_create = false completed_switch = false - -- completed_delete = false + completed_delete = false end before_each(function() @@ -28,9 +29,10 @@ describe('[Worktree]', function() print('called create') completed_create = true end, - -- DELETE = function() - -- completed_delete = true - -- end, + DELETE = function() + print('called delete') + completed_delete = true + end, SWITCH = function() completed_switch = true end, @@ -53,7 +55,7 @@ describe('[Worktree]', function() local path = '../' .. wt git_worktree:switch_worktree(path) -- - vim.fn.wait(10000, function() + vim.wait(10000, function() return completed_switch end, 1000) -- @@ -71,7 +73,7 @@ describe('[Worktree]', function() local path = '../' .. wt git_worktree:switch_worktree(path) -- - vim.fn.wait(10000, function() + vim.wait(10000, function() return completed_switch end, 1000) -- @@ -81,6 +83,7 @@ describe('[Worktree]', function() end) end) end) + -- luacheck: globals working_dir master_dir describe('[CREATE]', function() describe('[bare repo]', function() @@ -92,7 +95,7 @@ describe('[Worktree]', function() local path = '../' .. wt git_worktree:create_worktree(path, wt) -- - vim.fn.wait(10000, function() + vim.wait(10000, function() -- need to wait for final switch return completed_switch end, 1000) @@ -112,7 +115,7 @@ describe('[Worktree]', function() local path = '../' .. wt git_worktree:create_worktree(path, wt) -- - vim.fn.wait(10000, function() + vim.wait(10000, function() return completed_switch end, 1000) -- @@ -123,4 +126,46 @@ describe('[Worktree]', function() end) end) end) + + -- luacheck: globals working_dir master_dir + describe('[DELETE]', function() + describe('[bare repo]', function() + before_each(function() + working_dir, master_dir = git_harness.prepare_repo_bare_worktree(2) + end) + it('able to create a worktree (relative path)', function() + local wt = 'featB' + local path = '../' .. wt + git_worktree:delete_worktree(path, true) + -- + vim.wait(10000, function() + Log.debug('comp_del: %s', completed_delete) + return completed_delete + end, 1000) + Log.debug('comp_del finished: %s', completed_delete) + -- + -- -- Check to make sure directory was switched + assert.is_true(completed_delete) + assert.are.same(master_dir, vim.loop.cwd()) + end) + end) + describe('[normal repo]', function() + before_each(function() + working_dir, master_dir = git_harness.prepare_repo_normal_worktree(1) + end) + it('able to create a worktree (relative path)', function() + local wt = 'featB' + local path = '../' .. wt + git_worktree:delete_worktree(path, wt) + -- + vim.wait(10000, function() + return completed_delete + end, 1000) + -- + -- -- Check to make sure directory was switched + assert.is_true(completed_delete) + assert.are.same(master_dir, vim.loop.cwd()) + end) + end) + end) end) From 3a1eacf6f5dc218daa080f0482df2c8c8165633b Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Sat, 30 Dec 2023 12:55:23 -0500 Subject: [PATCH 19/33] refactor: delete worktree --- lua/git-worktree/enum.lua | 22 ---------- lua/git-worktree/status.lua | 83 ------------------------------------- 2 files changed, 105 deletions(-) delete mode 100644 lua/git-worktree/enum.lua delete mode 100644 lua/git-worktree/status.lua diff --git a/lua/git-worktree/enum.lua b/lua/git-worktree/enum.lua deleted file mode 100644 index 47ab23a..0000000 --- a/lua/git-worktree/enum.lua +++ /dev/null @@ -1,22 +0,0 @@ --- --- @class GitWorktreeOperation --- --- --- @return GitWorktreeOperation: A enum reperesenting worktree operation being performed --- local Enum = function(tbl) --- return setmetatable(tbl, { --- __index = function(_, key) --- error(string.format("%s does not exist for this enum.", key)) --- end, --- --- __newindex = function(_, _, _) --- error("Enums are immutable. You are not able to set new values") --- end, --- }) --- end --- --- return { --- Operation = Enum({ --- Create = "create", --- Switch = "switch", --- Delete = "delete", --- }), --- } diff --git a/lua/git-worktree/status.lua b/lua/git-worktree/status.lua deleted file mode 100644 index b917f05..0000000 --- a/lua/git-worktree/status.lua +++ /dev/null @@ -1,83 +0,0 @@ ----@class GitWorktreeLog ----@field logger any the plenary logging object -local M = {} - ----@return string -local function set_log_level() - local log_levels = { 'trace', 'debug', 'info', 'warn', 'error', 'fatal' } - local log_level = vim.env.GIT_WORKTREE_NVIM_LOG or vim.g.git_worktree_log_level - - for _, level in pairs(log_levels) do - if level == log_level then - return log_level - end - end - - return 'warn' -- default, if user hasn't set to one from log_levels -end - ----@return GitWorktreeLog -function M:new(options) - local obj = vim.tbl_extend('force', { - -- What to do here? - logger = require('plenary.log').new { - plugin = 'git-worktree-nvim', - level = set_log_level(), - }, - }, options or {}) - - setmetatable(obj, self) - self.__index = self - - return obj -end - ----Resets the count and index on the status logger ---- ----@param count integer -function M:reset(count) - self.count = count - self.idx = 0 -end - ----@param msg string -function M:_get_string(msg) - return string.format('%d / %d: %s', self.idx, self.count, msg) -end - ----@param msg string -function M:next_status(msg) - self.idx = self.idx + 1 - local fmt_msg = self:_get_string(msg) - print(fmt_msg) - self.logger.info(fmt_msg) -end - ----@param msg string -function M:next_error(msg) - self.idx = self.idx + 1 - local fmt_msg = self:_get_string(msg) - error(fmt_msg) - self.logger.error(fmt_msg) -end - ----@param msg string -function M:status(msg) - local fmt_msg = self:_get_string(msg) - print(fmt_msg) - self.logger.info(fmt_msg) -end - ----@param msg string -function M:error(msg) - local fmt_msg = self:_get_string(msg) - error(fmt_msg) - self.logger.error(fmt_msg) -end - ----@return GitWorktreeLog -function M:log() - return self.logger -end - -return M From 6494af86e811dca3ccbc94f429b0c0144e97cc2e Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 4 Jan 2024 14:58:03 -0500 Subject: [PATCH 20/33] refactor: add back in telescope --- flake.lock | 59 ++- flake.nix | 13 +- lua/git-worktree/git.lua | 109 +----- lua/git-worktree/git_spec.lua | 6 - lua/git-worktree/hooks.lua | 29 -- lua/telescope/_extensions/git_worktree.lua | 432 ++++++++++----------- 6 files changed, 291 insertions(+), 357 deletions(-) diff --git a/flake.lock b/flake.lock index c2f2a63..06bcec6 100644 --- a/flake.lock +++ b/flake.lock @@ -38,6 +38,24 @@ "inputs": { "systems": "systems" }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, "locked": { "lastModified": 1685518550, "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", @@ -89,6 +107,29 @@ "type": "github" } }, + "neovim": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "dir": "contrib", + "lastModified": 1704031853, + "narHash": "sha256-DOxfnhrIdTDWb+b9vKiuXq7zGTIhzC4g0EEP1uh36xs=", + "owner": "neovim", + "repo": "neovim", + "rev": "6fa0f303d7f0823bfc5ba6cc7b4e7a7cd76143ac", + "type": "github" + }, + "original": { + "dir": "contrib", + "owner": "neovim", + "repo": "neovim", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1703499205, @@ -158,7 +199,7 @@ "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat", - "flake-utils": "flake-utils", + "flake-utils": "flake-utils_2", "gitignore": "gitignore", "nixpkgs": [ "nixpkgs" @@ -183,6 +224,7 @@ "inputs": { "flake-parts": "flake-parts", "neodev-nvim": "neodev-nvim", + "neovim": "neovim", "nixpkgs": "nixpkgs", "plenary-nvim": "plenary-nvim", "pre-commit-hooks": "pre-commit-hooks", @@ -204,6 +246,21 @@ "type": "github" } }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "telescope-nvim": { "flake": false, "locked": { diff --git a/flake.nix b/flake.nix index b0e4798..6317377 100644 --- a/flake.nix +++ b/flake.nix @@ -9,6 +9,10 @@ inputs.nixpkgs.follows = "nixpkgs"; }; + neovim = { + url = "github:neovim/neovim?dir=contrib"; + inputs.nixpkgs.follows = "nixpkgs"; + }; neodev-nvim = { url = "github:folke/neodev.nvim"; flake = false; @@ -55,6 +59,9 @@ _module.args.pkgs = import inputs.nixpkgs { inherit system; overlays = [ + (final: _: { + neovim-nightly = inputs.neovim.packages.${final.system}.neovim; + }) ]; }; devShells = { @@ -81,12 +88,6 @@ name = "telescope.nvim"; src = inputs.telescope-nvim; }; - packages.neorocks-test-stable = pkgs.callPackage ./nix/neorocks-test.nix { - name = "git-worktree-stable"; - inherit self; - nvim = pkgs.neovim-unwrapped; - inherit (config.packages) plenary-plugin; - }; checks = { inherit pre-commit-check; diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index 1c94fdb..adc9474 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -57,54 +57,6 @@ function M.has_worktree(path_str, cb) job:start() end --- --- @return boolean --- function M.is_bare_repo() --- local inside_worktree_job = Job:new({ --- "git", --- "rev-parse", --- "--is-bare-repository", --- cwd = vim.loop.cwd(), --- }) --- --- local stdout, code = inside_worktree_job:sync() --- if code ~= 0 then --- status:log().error("Error in determining if we are in a worktree") --- return false --- end --- --- stdout = table.concat(stdout, "") --- --- if stdout == "true" then --- return true --- else --- return false --- end --- end --- --- --- @return boolean --- function M.is_worktree() --- local inside_worktree_job = Job:new({ --- "git", --- "rev-parse", --- "--is-inside-work-tree", --- cwd = vim.loop.cwd(), --- }) --- --- local stdout, code = inside_worktree_job:sync() --- if code ~= 0 then --- status:log().error("Error in determining if we are in a worktree") --- return false --- end --- --- stdout = table.concat(stdout, "") --- --- if stdout == "true" then --- return true --- else --- return false --- end --- end - --- @return string|nil function M.gitroot_dir() local job = Job:new { @@ -113,20 +65,20 @@ function M.gitroot_dir() '--path-format=absolute', '--git-common-dir', cwd = vim.loop.cwd(), - -- on_stderr = function(_, data) - -- status:log().info('ERROR: ' .. data) - -- end, + on_stderr = function(_, data) + Log.error('ERROR: ' .. data) + end, } local stdout, code = job:sync() if code ~= 0 then - -- status:log().error( - -- 'Error in determining the git root dir: code:' - -- .. tostring(code) - -- .. ' out: ' - -- .. table.concat(stdout, '') - -- .. '.' - -- ) + Log.error( + 'Error in determining the git root dir: code:' + .. tostring(code) + .. ' out: ' + .. table.concat(stdout, '') + .. '.' + ) return nil end @@ -141,20 +93,20 @@ function M.toplevel_dir() '--path-format=absolute', '--show-toplevel', cwd = vim.loop.cwd(), - -- on_stderr = function(_, data) - -- status:log().info('ERROR: ' .. data) - -- end, + on_stderr = function(_, data) + Log.error('ERROR: ' .. data) + end, } local stdout, code = job:sync() if code ~= 0 then - -- status:log().error( - -- 'Error in determining the git root dir: code:' - -- .. tostring(code) - -- .. ' out: ' - -- .. table.concat(stdout, '') - -- .. '.' - -- ) + Log.error( + 'Error in determining the git root dir: code:' + .. tostring(code) + .. ' out: ' + .. table.concat(stdout, '') + .. '.' + ) return nil end @@ -180,27 +132,6 @@ function M.has_branch(branch, cb) cb(found) end):start() end --- --- function M.has_origin() --- local found = false --- local job = Job:new({ --- "git", --- "remote", --- "show", --- on_stdout = function(_, data) --- data = vim.trim(data) --- found = found or data == "origin" --- end, --- cwd = vim.loop.cwd(), --- }) --- --- -- TODO: I really don't want status's spread everywhere... seems bad --- job:after(function() --- status:status("found origin: " .. tostring(found)) --- end):sync() --- --- return found --- end --- @param path string --- @param branch string diff --git a/lua/git-worktree/git_spec.lua b/lua/git-worktree/git_spec.lua index 97862dc..6574104 100644 --- a/lua/git-worktree/git_spec.lua +++ b/lua/git-worktree/git_spec.lua @@ -1,8 +1,5 @@ local git_harness = require('git-worktree.test.git_util') local gwt_git = require('git-worktree.git') -local Status = require('git-worktree.status') - -local status = Status:new() -- local wait_for_result = function(job, result) -- if type(result) == 'string' then @@ -20,7 +17,6 @@ describe('git-worktree git operations', function() describe('in normal repo', function() before_each(function() working_dir, master_dir = git_harness.prepare_repo() - status:reset(0) end) after_each(function() vim.api.nvim_command('cd ' .. cwd) @@ -99,7 +95,6 @@ describe('git-worktree git operations', function() describe('in bare repo', function() before_each(function() working_dir = git_harness.prepare_repo_bare() - status:reset(0) end) after_each(function() vim.api.nvim_command('cd ' .. cwd) @@ -177,7 +172,6 @@ describe('git-worktree git operations', function() describe('in worktree repo', function() before_each(function() working_dir, master_dir = git_harness.prepare_repo_bare_worktree(1) - status:reset(0) end) after_each(function() vim.api.nvim_command('cd ' .. cwd) diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 8cfae90..5815b7c 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -1,7 +1,3 @@ --- local Enum = require("git-worktree.enum") --- local Status = require("git-worktree.status") --- local status = Status:new() - --- @class GitWorkTreeHook --- @field SWITCH? fun(...): nil @@ -47,29 +43,4 @@ M.hook_event_names = { SWITCH = 'SWITCH', } --- function M.on_tree_change_handler(op, metadata) --- if M._config.update_on_change then --- if op == Enum.Operations.Switch then --- local changed = M.update_current_buffer(metadata["prev_path"]) --- if not changed then --- status --- :log() --- .debug("Could not change to the file in the new worktree, --- running the `update_on_change_command`") --- vim.cmd(M._config.update_on_change_command) --- end --- end --- end --- end - --- function M.emit_on_change(op, metadata) --- -- TODO: We don't have a way to async update what is running --- status:next_status(string.format("Running post %s callbacks", op)) --- print(metadata) --- -- on_tree_change_handler(op, metadata) --- -- for idx = 1, #on_change_callbacks do --- -- on_change_callbacks[idx](op, metadata) --- -- end --- end - return M diff --git a/lua/telescope/_extensions/git_worktree.lua b/lua/telescope/_extensions/git_worktree.lua index 5cc7862..7d2cf46 100644 --- a/lua/telescope/_extensions/git_worktree.lua +++ b/lua/telescope/_extensions/git_worktree.lua @@ -1,230 +1,210 @@ --- local strings = require("plenary.strings") --- local pickers = require("telescope.pickers") --- local finders = require("telescope.finders") --- local actions = require("telescope.actions") --- local utils = require("telescope.utils") --- local action_set = require("telescope.actions.set") --- local action_state = require("telescope.actions.state") --- local conf = require("telescope.config").values --- local git_worktree = require("git-worktree") - --- local force_next_deletion = false --- --- local get_worktree_path = function(prompt_bufnr) --- local selection = action_state.get_selected_entry(prompt_bufnr) --- return selection.path --- end --- --- local switch_worktree = function(prompt_bufnr) --- local worktree_path = get_worktree_path(prompt_bufnr) --- actions.close(prompt_bufnr) --- if worktree_path ~= nil then --- git_worktree.switch_worktree(worktree_path) --- end --- end --- --- local toggle_forced_deletion = function() --- -- redraw otherwise the message is not displayed when in insert mode --- if force_next_deletion then --- print("The next deletion will not be forced") --- vim.fn.execute("redraw") --- else --- print("The next deletion will be forced") --- vim.fn.execute("redraw") --- force_next_deletion = true --- end --- end --- --- local delete_success_handler = function() --- force_next_deletion = false --- end --- --- local delete_failure_handler = function() --- print("Deletion failed, use to force the next deletion") --- end --- --- local ask_to_confirm_deletion = function(forcing) --- if forcing then --- return vim.fn.input("Force deletion of worktree? [y/n]: ") --- end --- --- return vim.fn.input("Delete worktree? [y/n]: ") --- end --- --- local confirm_deletion = function(forcing) --- if not git_worktree._config.confirm_telescope_deletions then --- return true --- end --- --- local confirmed = ask_to_confirm_deletion(forcing) --- --- if string.sub(string.lower(confirmed), 0, 1) == "y" then --- return true --- end --- --- print("Didn't delete worktree") --- return false --- end --- --- local delete_worktree = function(prompt_bufnr) --- if not confirm_deletion() then --- return --- end --- --- local worktree_path = get_worktree_path(prompt_bufnr) --- actions.close(prompt_bufnr) --- if worktree_path ~= nil then --- git_worktree.delete_worktree(worktree_path, force_next_deletion, { --- on_failure = delete_failure_handler, --- on_success = delete_success_handler, --- }) --- end --- end --- --- local create_input_prompt = function(cb) --- --[[ --- local window = Window.centered({ --- width = 30, --- height = 1 --- }) --- vim.api.nvim_buf_set_option(window.bufnr, "buftype", "prompt") --- vim.fn.prompt_setprompt(window.bufnr, "Worktree Location: ") --- vim.fn.prompt_setcallback(window.bufnr, function(text) --- vim.api.nvim_win_close(window.win_id, true) --- vim.api.nvim_buf_delete(window.bufnr, {force = true}) --- cb(text) --- end) --- --- vim.api.nvim_set_current_win(window.win_id) --- vim.fn.schedule(function() --- vim.nvim_command("startinsert") --- end) --- --]] --- -- --- --- local subtree = vim.fn.input("Path to subtree > ") --- cb(subtree) --- end --- --- local create_worktree = function(opts) --- opts = opts or {} --- opts.attach_mappings = function() --- actions.select_default:replace(function(prompt_bufnr, _) --- local selected_entry = action_state.get_selected_entry() --- local current_line = action_state.get_current_line() --- --- actions.close(prompt_bufnr) --- --- local branch = selected_entry ~= nil and selected_entry.value or current_line --- --- if branch == nil then --- return --- end --- --- create_input_prompt(function(name) --- if name == "" then --- name = branch --- end --- git_worktree.create_worktree(name, branch) --- end) --- end) --- --- -- do we need to replace other default maps? --- --- return true --- end --- require("telescope.builtin").git_branches(opts) --- end --- --- local telescope_git_worktree = function(opts) --- opts = opts or {} --- local output = utils.get_os_command_output({ "git", "worktree", "list" }) --- local results = {} --- local widths = { --- path = 0, --- sha = 0, --- branch = 0, --- } --- --- local parse_line = function(line) --- local fields = vim.split(string.gsub(line, "%s+", " "), " ") --- local entry = { --- path = fields[1], --- sha = fields[2], --- branch = fields[3], --- } --- --- if entry.sha ~= "(bare)" then --- local index = #results + 1 --- for key, val in pairs(widths) do --- if key == "path" then --- local new_path = utils.transform_path(opts, entry[key]) --- local path_len = strings.strdisplaywidth(new_path or "") --- widths[key] = math.max(val, path_len) --- else --- widths[key] = math.max(val, strings.strdisplaywidth(entry[key] or "")) --- end --- end --- --- table.insert(results, index, entry) --- end --- end --- --- for _, line in ipairs(output) do --- parse_line(line) --- end --- --- if #results == 0 then --- return --- end --- --- local displayer = require("telescope.pickers.entry_display").create({ --- separator = " ", --- items = { --- { width = widths.branch }, --- { width = widths.path }, --- { width = widths.sha }, --- }, --- }) --- --- local make_display = function(entry) --- return displayer({ --- { entry.branch, "TelescopeResultsIdentifier" }, --- { utils.transform_path(opts, entry.path) }, --- { entry.sha }, --- }) --- end --- --- pickers --- .new(opts or {}, { --- prompt_title = "Git Worktrees", --- finder = finders.new_table({ --- results = results, --- entry_maker = function(entry) --- entry.value = entry.branch --- entry.ordinal = entry.branch --- entry.display = make_display --- return entry --- end, --- }), --- sorter = conf.generic_sorter(opts), --- attach_mappings = function(_, map) --- action_set.select:replace(switch_worktree) --- --- map("i", "", delete_worktree) --- map("n", "", delete_worktree) --- map("i", "", toggle_forced_deletion) --- map("n", "", toggle_forced_deletion) --- --- return true --- end, --- }) --- :find() --- end --- +local strings = require('plenary.strings') +local pickers = require('telescope.pickers') +local finders = require('telescope.finders') +local actions = require('telescope.actions') +local utils = require('telescope.utils') +local action_set = require('telescope.actions.set') +local action_state = require('telescope.actions.state') +local conf = require('telescope.config').values +local git_worktree = require('git-worktree') + +local force_next_deletion = false + +local get_worktree_path = function(prompt_bufnr) + local selection = action_state.get_selected_entry(prompt_bufnr) + return selection.path +end + +local switch_worktree = function(prompt_bufnr) + local worktree_path = get_worktree_path(prompt_bufnr) + actions.close(prompt_bufnr) + if worktree_path ~= nil then + git_worktree:switch_worktree(worktree_path) + end +end + +local toggle_forced_deletion = function() + -- redraw otherwise the message is not displayed when in insert mode + if force_next_deletion then + print('The next deletion will not be forced') + vim.fn.execute('redraw') + else + print('The next deletion will be forced') + vim.fn.execute('redraw') + force_next_deletion = true + end +end + +local delete_success_handler = function() + force_next_deletion = false +end + +local delete_failure_handler = function() + print('Deletion failed, use to force the next deletion') +end + +local ask_to_confirm_deletion = function(forcing) + if forcing then + return vim.fn.input('Force deletion of worktree? [y/n]: ') + end + + return vim.fn.input('Delete worktree? [y/n]: ') +end + +local confirm_deletion = function(forcing) + if not git_worktree._config.confirm_telescope_deletions then + return true + end + + local confirmed = ask_to_confirm_deletion(forcing) + + if string.sub(string.lower(confirmed), 0, 1) == 'y' then + return true + end + + print("Didn't delete worktree") + return false +end + +local delete_worktree = function(prompt_bufnr) + if not confirm_deletion() then + return + end + + local worktree_path = get_worktree_path(prompt_bufnr) + actions.close(prompt_bufnr) + if worktree_path ~= nil then + git_worktree.delete_worktree(worktree_path, force_next_deletion, { + on_failure = delete_failure_handler, + on_success = delete_success_handler, + }) + end +end + +local telescope_git_worktree = function(opts) + opts = opts or {} + local output = utils.get_os_command_output { 'git', 'worktree', 'list' } + local results = {} + local widths = { + path = 0, + sha = 0, + branch = 0, + } + + local parse_line = function(line) + local fields = vim.split(string.gsub(line, '%s+', ' '), ' ') + local entry = { + path = fields[1], + sha = fields[2], + branch = fields[3], + } + + if entry.sha ~= '(bare)' then + local index = #results + 1 + for key, val in pairs(widths) do + if key == 'path' then + local new_path = utils.transform_path(opts, entry[key]) + local path_len = strings.strdisplaywidth(new_path or '') + widths[key] = math.max(val, path_len) + else + widths[key] = math.max(val, strings.strdisplaywidth(entry[key] or '')) + end + end + + table.insert(results, index, entry) + end + end + + for _, line in ipairs(output) do + parse_line(line) + end + + if #results == 0 then + return + end + + local displayer = require('telescope.pickers.entry_display').create { + separator = ' ', + items = { + { width = widths.branch }, + { width = widths.path }, + { width = widths.sha }, + }, + } + + local make_display = function(entry) + return displayer { + { entry.branch, 'TelescopeResultsIdentifier' }, + { utils.transform_path(opts, entry.path) }, + { entry.sha }, + } + end + + pickers + .new(opts or {}, { + prompt_title = 'Git Worktrees', + finder = finders.new_table { + results = results, + entry_maker = function(entry) + entry.value = entry.branch + entry.ordinal = entry.branch + entry.display = make_display + return entry + end, + }, + sorter = conf.generic_sorter(opts), + attach_mappings = function(_, map) + action_set.select:replace(switch_worktree) + + map('i', '', delete_worktree) + map('n', '', delete_worktree) + map('i', '', toggle_forced_deletion) + map('n', '', toggle_forced_deletion) + + return true + end, + }) + :find() +end + +local create_input_prompt = function(cb) + local subtree = vim.fn.input('Path to subtree > ') + cb(subtree) +end + +local create_worktree = function(opts) + opts = opts or {} + opts.attach_mappings = function() + actions.select_default:replace(function(prompt_bufnr, _) + local selected_entry = action_state.get_selected_entry() + local current_line = action_state.get_current_line() + + actions.close(prompt_bufnr) + + local branch = selected_entry ~= nil and selected_entry.value or current_line + + if branch == nil then + return + end + + create_input_prompt(function(name) + if name == '' then + name = branch + end + git_worktree.create_worktree(name, branch) + end) + end) + + -- do we need to replace other default maps? + + return true + end + require('telescope.builtin').git_branches(opts) +end + return require('telescope').register_extension { exports = { - -- git_worktree = telescope_git_worktree, - -- create_git_worktree = create_worktree, + git_worktree = telescope_git_worktree, + create_git_worktree = create_worktree, }, } From ee1030d6b987f381c05f7228565a63e124e93ad3 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 4 Jan 2024 15:16:31 -0500 Subject: [PATCH 21/33] ci: add windows-latest test --- .github/workflows/ci.yml | 28 ++++++++++++++++++++-------- Makefile | 4 ++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c2d1f5..b56f962 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v4 - uses: rhysd/action-setup-vim@v1 @@ -23,24 +23,36 @@ jobs: with: luaVersion: "luajit-2.1.0-beta3" - - name: luarocks - uses: leafo/gh-actions-luarocks@v4 + - uses: notomo/action-setup-nvim-lua@v1 + - run: luarocks install vusted + - run: luarocks install luacheck - name: install plenary.nvim + if: matrix.os != 'windows-latest' run: | git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary - # git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim - - name: setup tools - shell: bash + - name: install plenary.nvim on windows + if: matrix.os == 'windows-latest' run: | - luarocks install luacheck - luarocks install vusted + git clone --depth 1 https://github.com/nvim-lua/plenary.nvim .\plenary + ls .\plenary + ls .\plenary\lua - name: Run tests + if: matrix.os != 'windows-latest' shell: bash env: VUSTED_NVIM: ${{ steps.vim.outputs.executable }} VUSTED_ARGS: "--headless" run: | make test + + - name: Run tests + if: matrix.os == 'windows-latest' + shell: bash + env: + VUSTED_NVIM: ${{ steps.vim.outputs.executable }} + VUSTED_ARGS: "--headless" + run: | + make wintest diff --git a/Makefile b/Makefile index f85615b..e9266c0 100644 --- a/Makefile +++ b/Makefile @@ -6,3 +6,7 @@ lint: .PHONY: test test: vusted --output=gtest ./lua + +.PHONY: wintest +wintest: + vusted --output=gtest -m '.\plenary\lua\?.lua' -m '.\plenary\lua\?\?.lua' -m '.\plenary\lua\?\init.lua' ./lua From 8408e076930bc23329c3d0b1742ba36653c2f745 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Mon, 22 Jan 2024 11:11:32 -0500 Subject: [PATCH 22/33] fix: add hook to update current buffer on switch --- lua/git-worktree/hooks.lua | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 5815b7c..bdb5a44 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -1,3 +1,5 @@ +local Path = require('plenary.path') + --- @class GitWorkTreeHook --- @field SWITCH? fun(...): nil @@ -33,8 +35,50 @@ function GitWorktreeHooks:emit(type, ...) end end +local builtins = {} + +builtins.update_current_buffer_on_switch = function(_, prev_path) + if prev_path == nil then + local gwt = require('git-worktree') + vim.cmd(gwt.config.update_on_change_command) + end + + local cwd = vim.loop.cwd() + local current_buf_name = vim.api.nvim_buf_get_name(0) + if not current_buf_name or current_buf_name == '' then + local gwt = require('git-worktree') + vim.cmd(gwt.config.update_on_change_command) + end + + local name = Path:new(current_buf_name):absolute() + local start1, _ = string.find(name, cwd .. Path.path.sep, 1, true) + if start1 ~= nil then + return + end + + local start, fin = string.find(name, prev_path, 1, true) + if start == nil then + local gwt = require('git-worktree') + vim.cmd(gwt.config.update_on_change_command) + end + + local local_name = name:sub(fin + 2) + + local final_path = Path:new({ cwd, local_name }):absolute() + + if not Path:new(final_path):exists() then + local gwt = require('git-worktree') + vim.cmd(gwt.config.update_on_change_command) + end + + local bufnr = vim.fn.bufnr(final_path, true) + vim.api.nvim_set_current_buf(bufnr) +end + local M = {} +M.builtins = builtins + M.hooks = GitWorktreeHooks:new() M.hook_event_names = { From 36091e6be0391c5a8a46c0f3a0ea4ad90885aed3 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Mon, 22 Jan 2024 13:01:40 -0500 Subject: [PATCH 23/33] docs: initial readme update --- README.md | 214 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 127 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index aaa8970..e54ecca 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,89 @@ # git-worktree.nvim -A simple wrapper around git worktree operations, create, switch, and delete. -There is some assumed workflow within this plugin, but pull requests are welcomed to -fix that). +
+ +[![Lua](https://img.shields.io/badge/Lua-blue.svg?style=for-the-badge&logo=lua)](http://www.lua.org) +[![Neovim](https://img.shields.io/badge/Neovim%200.8+-green.svg?style=for-the-badge&logo=neovim)](https://neovim.io) + +
+ +## TOC - [git-worktree.nvim](#git-worktreenvim) - - [Known Issues](#known-issues) - - [Dependencies](#dependencies) + - [TOC](#toc) + - [About](#about) + - [Installation](#installation) - [Getting Started](#getting-started) - - [Setup](#setup) + - [Basic Setup](#basic-setup) + - [Telescope Config](#telescope-config) + - [Config](#config) + - [Usage](#usage) + - [Hooks](#hooks) + - [Save](#save) - [Repository](#repository) - - [Options](#options) - - [Usage](#usage) - - [Telescope](#telescope) - - [Hooks](#hooks) - - [Made with fury](#made-with-fury) + - [Debugging](#debugging) + - [Troubleshooting](#troubleshooting) + - [Switch and Delete a worktrees](#switch-and-delete-a-worktrees) + - [Create a worktree](#create-a-worktree) -## Known Issues -There are a few known issues. I'll try to be actively filing them in the issues. If you experience something, and it's not an issue, feel free to make an issue! Even if it's a dupe I am just happy for the contribution. +## About -## Dependencies - -Requires NeoVim 0.5+ -Requires plenary.nvim -Optional telescope.nvim for telescope extension +A simple wrapper around git worktree operations, create, switch, and delete. +There is some assumed workflow within this plugin, but pull requests are +welcomed to fix that). -## Getting Started +## Installation -First, install the plugin the usual way you prefer. +- neovim 0.8.0+ required +- install using your favorite plugin manager +- or install using [lazy.nvim](https://github.com/folke/lazy.nvim) -```console -Plug 'ThePrimeagen/git-worktree.nvim' +```lua +{ + "polarmutex/git-worktree.nvim", + branch = "v2", + dependencies = { "nvim-lua/plenary.nvim" } +} ``` -Next, re-source your `vimrc`/`init.vim` and execute `PlugInstall` to ensure you have the plugin -installed. +- Optional: install telescope.nvim for telescope extension -## Setup +## Getting Started -## Repository +### Basic Setup -This repository does work best with a bare repo. To clone a bare repo, do the following. +```lua +local gwt = require("git-worktree") +local Hooks = require("git-worktree.hooks") -```shell -git clone --bare +-- REQUIRED +gwt:setup() +-- REQUIRED + +-- you probably want al least this basic hook to change current buffer +-- on worktree switch, more on hook below +gwt:hooks({ + SWITCH = Hooks.builtins.update_current_buffer_on_switch +}) ``` -If you do not use a bare repo, using telescope create command will be more helpful in the process of creating a branch. +### Telescope Config -### Debugging -git-worktree writes logs to a `git-worktree-nvim.log` file that resides in Neovim's cache path. (`:echo stdpath("cache")` to find where that is for you.) +In order to use [Telescope](https://github.com/nvim-telescope/telescope.nvim) as a UI, +make sure to add `telescope` to your dependencies and paste this following snippet into your configuration. -By default, logging is enabled for warnings and above. This can be changed by setting `vim.g.git_worktree_log_level` variable to one of the following log levels: `trace`, `debug`, `info`, `warn`, `error`, or `fatal`. Note that this would have to be done **before** git-worktree's `setup` call. Alternatively, it can be more convenient to launch Neovim with an environment variable, e.g. `> GIT_WORKTREE_NVIM_LOG=trace nvim`. In case both, `vim.g` and an environment variable are used, the log level set by the environment variable overrules. Supplying an invalid log level defaults back to warnings. +```lua +local gwt = require('git-worktree') +gwt:setup({}) -### Troubleshooting -If the upstream is not setup correctly when trying to pull or push, make sure the following command returns what is shown below. This seems to happen with the gitHub cli. +require('telescope').load_extension('git_worktree') ``` -git config --get remote.origin.fetch -+refs/heads/*:refs/remotes/origin/* -``` -if it does not run the following -``` -git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" -``` - -## Options +### Config `change_directory_command`: The vim command used to change to the new worktree directory. Set this to `tcd` if you want to only change the `pwd` for the current vim Tab. @@ -88,7 +102,8 @@ edit the wrong files. `autopush`: When creating a new worktree, it will push the branch to the upstream then perform a `git rebase` ```lua -require("git-worktree").setup({ +local gwt = require('git-worktree') +gwt:setup({ change_directory_command = -- default: "cd", update_on_change = -- default: true, update_on_change_command = -- default: "e .", @@ -97,7 +112,7 @@ require("git-worktree").setup({ }) ``` -## Usage +### Usage Three primary functions should cover your day-to-day. @@ -106,55 +121,26 @@ The path can be either relative from the git root dir or absolute path to the wo ```lua -- Creates a worktree. Requires the path, branch name, and the upstream -- Example: -:lua require("git-worktree").create_worktree("feat-69", "master", "origin") +:lua require("git-worktree"):create_worktree("feat-69", "master", "origin") -- switches to an existing worktree. Requires the path name -- Example: -:lua require("git-worktree").switch_worktree("feat-69") +:lua require("git-worktree"):switch_worktree("feat-69") -- deletes to an existing worktree. Requires the path name -- Example: -:lua require("git-worktree").delete_worktree("feat-69") -``` - -## Telescope - -Add the following to your vimrc to load the telescope extension - -```lua -require("telescope").load_extension("git_worktree") -``` - -### Switch and Delete a worktrees -To bring up the telescope window listing your workspaces run the following - -```lua -:lua require('telescope').extensions.git_worktree.git_worktrees() --- - switches to that worktree --- - deletes that worktree --- - toggles forcing of the next deletion +:lua require("git-worktree"):delete_worktree("feat-69") ``` -### Create a worktree -To bring up the telescope window to create a new worktree run the following - -```lua -:lua require('telescope').extensions.git_worktree.create_git_worktree() -``` -First a telescope git branch window will appear. Pressing enter will choose the selected branch for the branch name. If no branch is selected, then the prompt will be used as the branch name. - -After the git branch window, a prompt will be presented to enter the path name to write the worktree to. - -As of now you can not specify the upstream in the telescope create workflow, however if it finds a branch of the same name in the origin it will use it - -## Hooks +### Hooks Yes! The best part about `git-worktree` is that it emits information so that you can act on it. ```lua -local Worktree = require("git-worktree") +local gwt = require("git-worktree") +-- TODO Update -- op = Operations.Switch, Operations.Create, Operations.Delete -- metadata = table of useful values (structure dependent on op) -- Switch @@ -167,9 +153,9 @@ local Worktree = require("git-worktree") -- Delete -- path = path where worktree deleted -Worktree.on_tree_change(function(op, metadata) - if op == Worktree.Operations.Switch then - print("Switched from " .. metadata.prev_path .. " to " .. metadata.path) +gwt:hooks({ + SWITCH = function(path, prev_path) + print("Switched from " .. prev_path .. " to " .. path) end end) ``` @@ -178,7 +164,61 @@ This means that you can use [harpoon](https://github.com/ThePrimeagen/harpoon) or other plugins to perform follow up operations that will help in turbo charging your development experience! -## Made with fury +## Save + +## Repository + +This repository does work best with a bare repo. To clone a bare repo, do the following. + +```shell +git clone --bare +``` + +If you do not use a bare repo, using telescope create command will be more helpful in the process of creating a branch. + +### Debugging + +git-worktree writes logs to a `git-worktree-nvim.log` file that resides in Neovim's cache path. (`:echo stdpath("cache")` to find where that is for you.) + +By default, logging is enabled for warnings and above. This can be changed by setting `vim.g.git_worktree_log_level` variable to one of the following log levels: `trace`, `debug`, `info`, `warn`, `error`, or `fatal`. Note that this would have to be done **before** git-worktree's `setup` call. Alternatively, it can be more convenient to launch Neovim with an environment variable, e.g. `> GIT_WORKTREE_NVIM_LOG=trace nvim`. In case both, `vim.g` and an environment variable are used, the log level set by the environment variable overrules. Supplying an invalid log level defaults back to warnings. + +### Troubleshooting + +If the upstream is not setup correctly when trying to pull or push, make sure the following command returns what is shown below. This seems to happen with the gitHub cli. + +``` +git config --get remote.origin.fetch + ++refs/heads/*:refs/remotes/origin/* +``` + +if it does not run the following -All plugins are made live on [Twitch](https://twitch.tv/ThePrimeagen) with love -and fury. Come and join! +``` +git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" +``` + +### Switch and Delete a worktrees + +To bring up the telescope window listing your workspaces run the following + +```lua +:lua require('telescope').extensions.git_worktree.git_worktrees() +-- - switches to that worktree +-- - deletes that worktree +-- - toggles forcing of the next deletion +``` + +### Create a worktree + +To bring up the telescope window to create a new worktree run the following + +```lua +:lua require('telescope').extensions.git_worktree.create_git_worktree() +``` + +First a telescope git branch window will appear. Pressing enter will choose the selected branch for the branch name. If no branch is selected, then the prompt will be used as the branch name. + +After the git branch window, a prompt will be presented to enter the path name to write the worktree to. + +As of now you can not specify the upstream in the telescope create workflow, however if it finds a branch of the same name in the origin it will use it From e445e86d53c58883b3bf5590b7ea56466748344e Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Mon, 5 Feb 2024 15:15:34 -0500 Subject: [PATCH 24/33] refactor: to plenary test and other --- .gitignore | 1 + Makefile | 3 +- README.md | 75 ++++----- flake.nix | 46 ++++-- lua/git-worktree/config.lua | 20 ++- lua/git-worktree/config_spec.lua | 9 +- lua/git-worktree/hooks.lua | 40 ++--- lua/git-worktree/init.lua | 42 +---- lua/git-worktree/logger.lua | 4 +- lua/git-worktree/worktree.lua | 30 ++-- lua/git-worktree/worktree_spec.lua | 175 ++++++++++----------- lua/telescope/_extensions/git_worktree.lua | 8 +- plugin/git-worktree.lua | 8 + 13 files changed, 238 insertions(+), 223 deletions(-) create mode 100644 plugin/git-worktree.lua diff --git a/.gitignore b/.gitignore index f9a759c..ae916d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .direnv .pre-commit-config.yaml +minimal.vim diff --git a/Makefile b/Makefile index e9266c0..716015e 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ lint: # GIT_WORKTREE_NVIM_LOG=fatal .PHONY: test test: - vusted --output=gtest ./lua + # minimal.vim is generated when entering the flake, aka `nix develop` + nvim --headless -u minimal.vim -c "lua require('plenary.test_harness').test_directory('.', {minimal_init='minimal.vim'})" .PHONY: wintest wintest: diff --git a/README.md b/README.md index e54ecca..1366d92 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,13 @@ - [git-worktree.nvim](#git-worktreenvim) - [TOC](#toc) - [About](#about) + - [Prerequisites](#prerequisites) + - [Optional](#optional) - [Installation](#installation) - - [Getting Started](#getting-started) - - [Basic Setup](#basic-setup) + - [Quick Setup](#quick-setup) - [Telescope Config](#telescope-config) - - [Config](#config) - - [Usage](#usage) + - [Usage](#usage) + - [Advanced Config](#advanced-config) - [Hooks](#hooks) - [Save](#save) - [Repository](#repository) @@ -36,9 +37,16 @@ A simple wrapper around git worktree operations, create, switch, and delete. There is some assumed workflow within this plugin, but pull requests are welcomed to fix that). +## Prerequisites + +- `neovim >= 0.8` + +### Optional + +- install telescope.nvim for telescope extension + ## Installation -- neovim 0.8.0+ required - install using your favorite plugin manager - or install using [lazy.nvim](https://github.com/folke/lazy.nvim) @@ -50,20 +58,20 @@ welcomed to fix that). } ``` -- Optional: install telescope.nvim for telescope extension - -## Getting Started +> \[!NOTE\] +> +> It is suggested to pin to tagged releases if you would like to avoid breaking changes. -### Basic Setup +## Quick Setup -```lua +``` local gwt = require("git-worktree") -local Hooks = require("git-worktree.hooks") -- REQUIRED gwt:setup() -- REQUIRED +local Hooks = require("git-worktree.hooks") -- you probably want al least this basic hook to change current buffer -- on worktree switch, more on hook below gwt:hooks({ @@ -77,13 +85,30 @@ In order to use [Telescope](https://github.com/nvim-telescope/telescope.nvim) as make sure to add `telescope` to your dependencies and paste this following snippet into your configuration. ```lua -local gwt = require('git-worktree') -gwt:setup({}) - require('telescope').load_extension('git_worktree') ``` -### Config +## Usage + +Three primary functions should cover your day-to-day. + +The path can be either relative from the git root dir or absolute path to the worktree. + +```lua +-- Creates a worktree. Requires the path, branch name, and the upstream +-- Example: +:lua require("git-worktree").create_worktree("feat-69", "master", "origin") + +-- switches to an existing worktree. Requires the path name +-- Example: +:lua require("git-worktree").switch_worktree("feat-69") + +-- deletes to an existing worktree. Requires the path name +-- Example: +:lua require("git-worktree").delete_worktree("feat-69") +``` + +## Advanced Config `change_directory_command`: The vim command used to change to the new worktree directory. Set this to `tcd` if you want to only change the `pwd` for the current vim Tab. @@ -112,26 +137,6 @@ gwt:setup({ }) ``` -### Usage - -Three primary functions should cover your day-to-day. - -The path can be either relative from the git root dir or absolute path to the worktree. - -```lua --- Creates a worktree. Requires the path, branch name, and the upstream --- Example: -:lua require("git-worktree"):create_worktree("feat-69", "master", "origin") - --- switches to an existing worktree. Requires the path name --- Example: -:lua require("git-worktree"):switch_worktree("feat-69") - --- deletes to an existing worktree. Requires the path name --- Example: -:lua require("git-worktree"):delete_worktree("feat-69") -``` - ### Hooks Yes! The best part about `git-worktree` is that it emits information so that you diff --git a/flake.nix b/flake.nix index 6317377..636c1d7 100644 --- a/flake.nix +++ b/flake.nix @@ -64,16 +64,42 @@ }) ]; }; - devShells = { - default = pkgs.mkShell { - name = "haskell-tools.nvim-shell"; - inherit (pre-commit-check) shellHook; - buildInputs = with pkgs; [ - luajitPackages.luacheck - luajitPackages.vusted - stylua - ]; - }; + devShells = let + mkDevShell = luaVersion: let + luaEnv = pkgs."lua${luaVersion}".withPackages (lp: + with lp; [ + busted + luacheck + luarocks + ]); + in + pkgs.mkShell { + name = "git-worktree-nvim"; + buildInputs = [ + luaEnv + ]; + shellHook = let + myVimPackage = with pkgs.vimPlugins; { + start = [ + plenary-nvim + ]; + }; + packDirArgs.myNeovimPackages = myVimPackage; + in + pre-commit-check.shellHook + + '' + export DEBUG_PLENARY="debug" + cat <<-EOF > minimal.vim + set rtp+=. + set packpath^=${pkgs.vimUtils.packDir packDirArgs} + EOF + ''; + }; + in { + default = mkDevShell "jit"; + luajit = mkDevShell "jit"; + lua-51 = mkDevShell "5_1"; + lua-52 = mkDevShell "5_2"; }; packages.neodev-plugin = pkgs.vimUtils.buildVimPlugin { diff --git a/lua/git-worktree/config.lua b/lua/git-worktree/config.lua index 73f75e1..a7f9a99 100644 --- a/lua/git-worktree/config.lua +++ b/lua/git-worktree/config.lua @@ -1,7 +1,7 @@ local M = {} ---@class GitWorktreeConfig -local defaults = { +local config = { -- command to change directory on your OS. -- @@ -34,14 +34,20 @@ local defaults = { autopush = false, } ---- @return GitWorktreeConfig -M._get_defaults = function() - return defaults +--- Get a configuration value +--- @param opt string +--- @return any +M.get = function() + return config end ----@param opts? GitWorktreeConfig -function M.setup(opts) - local config = vim.tbl_deep_extend('force', vim.deepcopy(defaults), opts or {}) +--- Set user configurations +--- @param user_configs table +--- @return table +M.set = function(user_configs) + vim.validate { user_configs = { user_configs, 'table' } } + + config = vim.tbl_deep_extend('force', config, user_configs) return config end diff --git a/lua/git-worktree/config_spec.lua b/lua/git-worktree/config_spec.lua index c054fb9..6d7b70c 100644 --- a/lua/git-worktree/config_spec.lua +++ b/lua/git-worktree/config_spec.lua @@ -3,16 +3,15 @@ local stub = require('luassert.stub') describe('config', function() local notify_once = stub(vim, 'notify_once') local notify = stub(vim, 'notify') - local Config = require('git-worktree.config') + local config = require('git-worktree.config') it('returns the default config', function() - local df = Config._get_defaults() - assert.truthy(df.change_directory_command) + assert.truthy(config.get().change_directory_command) end) it('can have configuration applied', function() - local cfg = Config.setup { change_directory_command = 'test' } - assert.equals(cfg.change_directory_command, 'test') + config.set { change_directory_command = 'test' } + assert.equals(config.get().change_directory_command, 'test') end) it('No notifications at startup.', function() diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index bdb5a44..9f9f551 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -2,34 +2,38 @@ local Path = require('plenary.path') --- @class GitWorkTreeHook --- @field SWITCH? fun(...): nil +--- @field CREATE? fun(...): nil +--- @field DELETE? fun(...): nil ---- @class GitWorktreeHooks ---- @field hooks GitWorktreeHook[] -local GitWorktreeHooks = {} +local M = {} + +local Hooks = {} -GitWorktreeHooks.__index = GitWorktreeHooks +Hooks.__index = Hooks -function GitWorktreeHooks:new() +function Hooks:new() return setmetatable({ hooks = {}, }, self) end ---@param hook GitWorktreeHook -function GitWorktreeHooks:add_listener(hook) +function Hooks:add_listener(hook) table.insert(self.hooks, hook) end -function GitWorktreeHooks:clear_listener() +function M:clear_listeners() self.hooks = {} end ---@param type string ---@param ... any -function GitWorktreeHooks:emit(type, ...) +function Hooks:emit(type, ...) + print('emitting') for _, cb in ipairs(self.hooks) do print(type) if cb[type] then + print(vim.inspect(cb)) cb[type](...) end end @@ -39,15 +43,15 @@ local builtins = {} builtins.update_current_buffer_on_switch = function(_, prev_path) if prev_path == nil then - local gwt = require('git-worktree') - vim.cmd(gwt.config.update_on_change_command) + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) end local cwd = vim.loop.cwd() local current_buf_name = vim.api.nvim_buf_get_name(0) if not current_buf_name or current_buf_name == '' then - local gwt = require('git-worktree') - vim.cmd(gwt.config.update_on_change_command) + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) end local name = Path:new(current_buf_name):absolute() @@ -58,8 +62,8 @@ builtins.update_current_buffer_on_switch = function(_, prev_path) local start, fin = string.find(name, prev_path, 1, true) if start == nil then - local gwt = require('git-worktree') - vim.cmd(gwt.config.update_on_change_command) + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) end local local_name = name:sub(fin + 2) @@ -67,20 +71,18 @@ builtins.update_current_buffer_on_switch = function(_, prev_path) local final_path = Path:new({ cwd, local_name }):absolute() if not Path:new(final_path):exists() then - local gwt = require('git-worktree') - vim.cmd(gwt.config.update_on_change_command) + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) end local bufnr = vim.fn.bufnr(final_path, true) vim.api.nvim_set_current_buf(bufnr) end -local M = {} +M.hooks = Hooks:new() M.builtins = builtins -M.hooks = GitWorktreeHooks:new() - M.hook_event_names = { CREATE = 'CREATE', DELETE = 'DELETE', diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index e0136d3..ce3a121 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -1,44 +1,18 @@ local Config = require('git-worktree.config') -local Hooks = require('git-worktree.hooks') local Worktree = require('git-worktree.worktree') ---- @class GitWorktree ---- @field config GitWorktreeConfig ---- @field _hooks GitWorktreeHooks - local M = {} -M.__index = M - -function M:new() - local config = Config._get_defaults() - local obj = setmetatable({ - config = config, - _hooks = Hooks.hooks, - }, self) - return obj -end - -local current = M:new() - ----@param self GitWorktree ---- @param opts table -function M.setup(self, opts) - if self ~= current then - self = current - end - self.config = Config.setup(opts) - return self -end ----@param hook GitWorkTreeHook -function M:hooks(hook) - self._hooks:add_listener(hook) +function M.setup(user_configs) + Config.set(user_configs or {}) + -- initialize hooks + require('git-worktree.hooks') end --Switch the current worktree ---@param path string -- luacheck:ignore self -function M:switch_worktree(path) +function M.switch_worktree(path) Worktree.switch(path) end @@ -47,7 +21,7 @@ end ---@param branch string ---@param upstream? string -- luacheck:ignore self -function M:create_worktree(path, branch, upstream) +function M.create_worktree(path, branch, upstream) Worktree.create(path, branch, upstream) end @@ -55,8 +29,8 @@ end ---@param path string ---@param force boolean ---@param opts any -function M:delete_worktree(path, force, opts) +function M.delete_worktree(path, force, opts) Worktree.delete(path, force, opts) end -return current +return M diff --git a/lua/git-worktree/logger.lua b/lua/git-worktree/logger.lua index 5e11aa5..69d4c26 100644 --- a/lua/git-worktree/logger.lua +++ b/lua/git-worktree/logger.lua @@ -28,8 +28,8 @@ local function log(level, msg) }) end -- vim.api.nvim_echo(msg_chunks, false, {}) - vim.notify(msg, level) - print(msg) + -- vim.notify(msg, level) + -- print(msg) end --- @param fmt string diff --git a/lua/git-worktree/worktree.lua b/lua/git-worktree/worktree.lua index d51c7bc..4c2fadd 100644 --- a/lua/git-worktree/worktree.lua +++ b/lua/git-worktree/worktree.lua @@ -1,6 +1,5 @@ local Path = require('plenary.path') -local Hooks = require('git-worktree.hooks') local Git = require('git-worktree.git') local Log = require('git-worktree.logger') @@ -13,22 +12,21 @@ local function get_absolute_path(path) end local function change_dirs(path) - local Gwt = require('git-worktree') Log.info('changing dirs: %s ', path) local worktree_path = get_absolute_path(path) local previous_worktree = vim.loop.cwd() + local config = require('git-worktree.config').get() -- vim.loop.chdir(worktree_path) - print(vim.inspect(Gwt)) if Path:new(worktree_path):exists() then - local cmd = string.format('%s %s', Gwt.config.change_directory_command, worktree_path) + local cmd = string.format('%s %s', config.change_directory_command, worktree_path) Log.debug('Changing to directory %s', worktree_path) vim.cmd(cmd) else Log.error('Could not chang to directory: %s', worktree_path) end - if Gwt.config.clearjumps_on_change then + if config.clearjumps_on_change then Log.debug('Clearing jumps') vim.cmd('clearjumps') end @@ -62,8 +60,6 @@ local M = {} --Switch the current worktree ---@param path string function M.switch(path) - local Gwt = require('git-worktree') - local cur_hooks = Gwt._hooks Git.has_worktree(path, function(found) Log.debug('test') if not found then @@ -73,7 +69,8 @@ function M.switch(path) vim.schedule(function() local prev_path = change_dirs(path) - cur_hooks:emit(Hooks.hook_event_names.SWITCH, path, prev_path) + local Hooks = require('git-worktree.hooks') + Hooks.hooks:emit(Hooks.hook_event_names.SWITCH, path, prev_path) end) end) end @@ -100,6 +97,7 @@ function M.create(path, branch, upstream) end Git.has_branch(branch, function(found_branch) + local config = require('git-worktree.config').get() local worktree_path if Path:new(path):is_absolute() then worktree_path = path @@ -110,9 +108,6 @@ function M.create(path, branch, upstream) -- create_worktree(path, branch, upstream, found_branch) local create_wt_job = Git.create_worktree_job(path, branch, found_branch) - local Gwt = require('git-worktree') - local cur_hooks = Gwt._hooks - if upstream ~= nil then local fetch = Git.fetchall_job(path, branch, upstream) local set_branch = Git.setbranch_job(path, branch, upstream) @@ -122,7 +117,7 @@ function M.create(path, branch, upstream) create_wt_job:and_then_on_success(fetch) fetch:and_then_on_success(set_branch) - if Gwt.config.autopush then + if config.autopush then -- These are "optional" operations. -- We have to figure out how we want to handle these... set_branch:and_then(set_push) @@ -143,14 +138,16 @@ function M.create(path, branch, upstream) end vim.schedule(function() - cur_hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) + local Hooks = require('git-worktree.hooks') + Hooks.hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) M.switch(path) end) end) else create_wt_job:after(function() vim.schedule(function() - cur_hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) + local Hooks = require('git-worktree.hooks') + Hooks.hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) M.switch(path) end) end) @@ -178,13 +175,12 @@ function M.delete(path, force, opts) else Log.info('Worktree %s does exist', path) end - local Gwt = require('git-worktree') - local cur_hooks = Gwt._hooks local delete = Git.delete_worktree_job(path, force) delete:after_success(vim.schedule_wrap(function() Log.info('delete after success') - cur_hooks:emit(Hooks.hook_event_names.DELETE, path) + local Hooks = require('git-worktree.hooks') + Hooks.hooks:emit(Hooks.hook_event_names.DELETE, path) if opts.on_success then opts.on_success() end diff --git a/lua/git-worktree/worktree_spec.lua b/lua/git-worktree/worktree_spec.lua index 93dac07..e1f9abc 100644 --- a/lua/git-worktree/worktree_spec.lua +++ b/lua/git-worktree/worktree_spec.lua @@ -1,46 +1,19 @@ local git_harness = require('git-worktree.test.git_util') -local git_worktree = require('git-worktree') -local Log = require('git-worktree.logger') local Path = require('plenary.path') --- local Status = require('git-worktree.status') - --- local status = Status:new() +local stub = require('luassert.stub') local cwd = vim.fn.getcwd() --- luacheck: globals repo_dir +-- luacheck: globals repo_dir config git_worktree describe('[Worktree]', function() - local completed_create = false - local completed_switch = false - local completed_delete = false - - local reset_variables = function() - completed_create = false - completed_switch = false - completed_delete = false - end + local Hooks = require('git-worktree.hooks').hooks + stub(Hooks, 'emit') before_each(function() - reset_variables() git_worktree = require('git-worktree') - git_worktree:setup {} - git_worktree:hooks { - CREATE = function() - print('called create') - completed_create = true - end, - DELETE = function() - print('called delete') - completed_delete = true - end, - SWITCH = function() - completed_switch = true - end, - } + git_worktree.setup {} end) - after_each(function() - -- git_worktree.reset() vim.api.nvim_command('cd ' .. cwd) end) @@ -52,34 +25,45 @@ describe('[Worktree]', function() end) it('able to switch to worktree (relative path)', function() local wt = 'featB' - local path = '../' .. wt - git_worktree:switch_worktree(path) - -- - vim.wait(10000, function() - return completed_switch + local input_path = '../' .. wt + local expected_path = working_dir .. Path.path.sep .. wt + local prev_path = working_dir .. Path.path.sep .. 'master' + require('git-worktree').switch_worktree(input_path) + + local co = coroutine.running() + vim.defer_fn(function() + coroutine.resume(co) end, 1000) - -- - -- -- Check to make sure directory was switched - assert.is_true(completed_switch) - assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) + --The test will reach here immediately. + coroutine.yield() + + -- Check to make sure directory was switched + assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) + assert.are.same(expected_path, vim.loop.cwd()) end) end) + describe('[normal repo]', function() before_each(function() working_dir, master_dir = git_harness.prepare_repo_normal_worktree(1) end) it('able to switch to worktree (relative path)', function() local wt = 'featB' - local path = '../' .. wt - git_worktree:switch_worktree(path) - -- - vim.wait(10000, function() - return completed_switch + local input_path = '../' .. wt + local expected_path = working_dir .. Path.path.sep .. wt + local prev_path = working_dir .. Path.path.sep .. 'master' + require('git-worktree').switch_worktree(input_path) + + local co = coroutine.running() + vim.defer_fn(function() + coroutine.resume(co) end, 1000) - -- - -- -- Check to make sure directory was switched - assert.is_true(completed_switch) - assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) + --The test will reach here immediately. + coroutine.yield() + + -- Check to make sure directory was switched + assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) + assert.are.same(expected_path, vim.loop.cwd()) end) end) end) @@ -92,18 +76,22 @@ describe('[Worktree]', function() end) it('able to create a worktree (relative path)', function() local wt = 'featB' - local path = '../' .. wt - git_worktree:create_worktree(path, wt) - -- - vim.wait(10000, function() - -- need to wait for final switch - return completed_switch + local input_path = '../' .. wt + local expected_path = working_dir .. Path.path.sep .. wt + local prev_path = working_dir .. Path.path.sep .. 'master' + require('git-worktree').create_worktree(input_path, wt) + + local co = coroutine.running() + vim.defer_fn(function() + coroutine.resume(co) end, 1000) - -- - -- -- Check to make sure directory was switched - assert.is_true(completed_create) - assert.is_true(completed_switch) - assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) + --The test will reach here immediately. + coroutine.yield() + + -- Check to make sure directory was switched + assert.stub(Hooks.emit).was_called_with(Hooks, 'CREATE', input_path, wt, nil) + assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) + assert.are.same(expected_path, vim.loop.cwd()) end) end) describe('[normal repo]', function() @@ -112,17 +100,22 @@ describe('[Worktree]', function() end) it('able to create a worktree (relative path)', function() local wt = 'featB' - local path = '../' .. wt - git_worktree:create_worktree(path, wt) - -- - vim.wait(10000, function() - return completed_switch + local input_path = '../' .. wt + local expected_path = working_dir .. Path.path.sep .. wt + local prev_path = working_dir .. Path.path.sep .. 'master' + require('git-worktree').create_worktree(input_path, wt) + + local co = coroutine.running() + vim.defer_fn(function() + coroutine.resume(co) end, 1000) - -- - -- -- Check to make sure directory was switched - assert.is_true(completed_create) - assert.is_true(completed_switch) - assert.are.same(working_dir .. Path.path.sep .. wt, vim.loop.cwd()) + --The test will reach here immediately. + coroutine.yield() + + -- Check to make sure directory was switched + assert.stub(Hooks.emit).was_called_with(Hooks, 'CREATE', input_path, wt, nil) + assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) + assert.are.same(expected_path, vim.loop.cwd()) end) end) end) @@ -135,17 +128,18 @@ describe('[Worktree]', function() end) it('able to create a worktree (relative path)', function() local wt = 'featB' - local path = '../' .. wt - git_worktree:delete_worktree(path, true) - -- - vim.wait(10000, function() - Log.debug('comp_del: %s', completed_delete) - return completed_delete + local input_path = '../' .. wt + require('git-worktree').delete_worktree(input_path, true) + + local co = coroutine.running() + vim.defer_fn(function() + coroutine.resume(co) end, 1000) - Log.debug('comp_del finished: %s', completed_delete) - -- - -- -- Check to make sure directory was switched - assert.is_true(completed_delete) + --The test will reach here immediately. + coroutine.yield() + + -- Check to make sure directory was switched + assert.stub(Hooks.emit).was_called_with(Hooks, 'DELETE', input_path) assert.are.same(master_dir, vim.loop.cwd()) end) end) @@ -155,15 +149,18 @@ describe('[Worktree]', function() end) it('able to create a worktree (relative path)', function() local wt = 'featB' - local path = '../' .. wt - git_worktree:delete_worktree(path, wt) - -- - vim.wait(10000, function() - return completed_delete + local input_path = '../' .. wt + require('git-worktree').delete_worktree(input_path, wt) + + local co = coroutine.running() + vim.defer_fn(function() + coroutine.resume(co) end, 1000) - -- - -- -- Check to make sure directory was switched - assert.is_true(completed_delete) + --The test will reach here immediately. + coroutine.yield() + + -- Check to make sure directory was switched + assert.stub(Hooks.emit).was_called_with(Hooks, 'DELETE', input_path) assert.are.same(master_dir, vim.loop.cwd()) end) end) diff --git a/lua/telescope/_extensions/git_worktree.lua b/lua/telescope/_extensions/git_worktree.lua index 7d2cf46..26aecef 100644 --- a/lua/telescope/_extensions/git_worktree.lua +++ b/lua/telescope/_extensions/git_worktree.lua @@ -26,10 +26,10 @@ end local toggle_forced_deletion = function() -- redraw otherwise the message is not displayed when in insert mode if force_next_deletion then - print('The next deletion will not be forced') + -- print('The next deletion will not be forced') vim.fn.execute('redraw') else - print('The next deletion will be forced') + -- print('The next deletion will be forced') vim.fn.execute('redraw') force_next_deletion = true end @@ -40,7 +40,7 @@ local delete_success_handler = function() end local delete_failure_handler = function() - print('Deletion failed, use to force the next deletion') + -- print('Deletion failed, use to force the next deletion') end local ask_to_confirm_deletion = function(forcing) @@ -62,7 +62,7 @@ local confirm_deletion = function(forcing) return true end - print("Didn't delete worktree") + -- print("Didn't delete worktree") return false end diff --git a/plugin/git-worktree.lua b/plugin/git-worktree.lua new file mode 100644 index 0000000..a618700 --- /dev/null +++ b/plugin/git-worktree.lua @@ -0,0 +1,8 @@ +if not vim.g.did_gitworktree_initialize then + vim.api.nvim_create_user_command('GitWorktreeSwitch', function(args) + local path = args['args'] + require('git-worktree').switch_worktree(path) + end, { desc = 'Switch to worktree', nargs = 1 }) +end + +vim.g.did_gitworktree_initialize = true From f37e1a2f020f4c788d1b0cf8d1462a640783cfb3 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Wed, 17 Jul 2024 22:56:50 -0400 Subject: [PATCH 25/33] refactor: final rework --- .busted | 13 + .gitignore | 1 + .luarc.json | 1 + flake.lock | 542 ++++++++++++++----- flake.nix | 145 +++-- lua/git-worktree/config.lua | 42 +- lua/git-worktree/git.lua | 38 +- lua/git-worktree/hooks.lua | 148 ++--- lua/git-worktree/init.lua | 7 - lua/git-worktree/setup_spec.lua | 5 - lua/git-worktree/worktree.lua | 15 +- lua/telescope/_extensions/git_worktree.lua | 113 ++-- nix/type-check.nix | 68 --- plugin/git-worktree.lua | 8 - {lua/git-worktree => spec}/config_spec.lua | 6 +- {lua/git-worktree => spec}/git_spec.lua | 0 {lua/git-worktree => spec}/worktree_spec.lua | 84 ++- 17 files changed, 771 insertions(+), 465 deletions(-) create mode 100644 .busted create mode 120000 .luarc.json delete mode 100644 lua/git-worktree/setup_spec.lua delete mode 100644 nix/type-check.nix delete mode 100644 plugin/git-worktree.lua rename {lua/git-worktree => spec}/config_spec.lua (72%) rename {lua/git-worktree => spec}/git_spec.lua (100%) rename {lua/git-worktree => spec}/worktree_spec.lua (63%) diff --git a/.busted b/.busted new file mode 100644 index 0000000..fa9d48a --- /dev/null +++ b/.busted @@ -0,0 +1,13 @@ +return { + _all = { + coverage = false, + lpath = 'lua/?.lua;lua/?/init.lua', + lua = 'nlua', + }, + default = { + verbose = true, + }, + tests = { + verbose = true, + }, +} diff --git a/.gitignore b/.gitignore index ae916d3..836f6ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .direnv .pre-commit-config.yaml minimal.vim +result diff --git a/.luarc.json b/.luarc.json new file mode 120000 index 0000000..8f4162f --- /dev/null +++ b/.luarc.json @@ -0,0 +1 @@ +/nix/store/k2cp6gm6qlcgvi8alp9kyz81bfgprrn5-luarc.json \ No newline at end of file diff --git a/flake.lock b/flake.lock index 06bcec6..9c349ed 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,75 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", "owner": "edolstra", "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_3": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_4": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_5": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", "type": "github" }, "original": { @@ -21,11 +85,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1701473968, - "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", + "lastModified": 1719994518, + "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5", + "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7", "type": "github" }, "original": { @@ -34,55 +98,169 @@ "type": "github" } }, - "flake-utils": { + "flake-parts_2": { "inputs": { - "systems": "systems" + "nixpkgs-lib": "nixpkgs-lib_2" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "lastModified": 1717285511, + "narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8", "type": "github" }, "original": { - "owner": "numtide", - "repo": "flake-utils", + "owner": "hercules-ci", + "repo": "flake-parts", "type": "github" } }, - "flake-utils_2": { + "flake-parts_3": { "inputs": { - "systems": "systems_2" + "nixpkgs-lib": "nixpkgs-lib_3" }, "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "lastModified": 1719994518, + "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7", "type": "github" }, "original": { - "owner": "numtide", - "repo": "flake-utils", + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_4": { + "inputs": { + "nixpkgs-lib": [ + "neorocks", + "neovim-nightly", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719994518, + "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_5": { + "inputs": { + "nixpkgs-lib": [ + "neorocks", + "neovim-nightly", + "hercules-ci-effects", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, + "gen-luarc": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1718922730, + "narHash": "sha256-ykhhOPqA9NzdNBr3ii+3h2DkK2+wasNqQLfMF6BXxTE=", + "owner": "mrcjkb", + "repo": "nix-gen-luarc-json", + "rev": "021e8078e43884c6cdc70ca753d9a0b146cd55a4", + "type": "github" + }, + "original": { + "owner": "mrcjkb", + "repo": "nix-gen-luarc-json", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat_2", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs_2", + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1721042469, + "narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "f451c19376071a90d8c58ab1a953c6e9840527fd", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "git-hooks_2": { + "inputs": { + "flake-compat": "flake-compat_4", + "gitignore": "gitignore_2", + "nixpkgs": [ + "neorocks", + "neovim-nightly", + "nixpkgs" + ], + "nixpkgs-stable": [ + "neorocks", + "neovim-nightly", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1721042469, + "narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "f451c19376071a90d8c58ab1a953c6e9840527fd", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", "type": "github" } }, "gitignore": { "inputs": { "nixpkgs": [ - "pre-commit-hooks", + "neorocks", + "git-hooks", "nixpkgs" ] }, "locked": { - "lastModified": 1660459072, - "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", "owner": "hercules-ci", "repo": "gitignore.nix", - "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { @@ -91,40 +269,129 @@ "type": "github" } }, - "neodev-nvim": { - "flake": false, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "neorocks", + "neovim-nightly", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_3": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, "locked": { - "lastModified": 1703570758, - "narHash": "sha256-tIRhHXu2rFIlTtXcHjEzWjqB4SZpTZch13VOecuplSA=", - "owner": "folke", - "repo": "neodev.nvim", - "rev": "029899ea32d3dc8ed8c910ceca2ee5d16e566c11", + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { - "owner": "folke", - "repo": "neodev.nvim", + "owner": "hercules-ci", + "repo": "gitignore.nix", "type": "github" } }, - "neovim": { + "hercules-ci-effects": { "inputs": { - "flake-utils": "flake-utils", + "flake-parts": "flake-parts_5", "nixpkgs": [ + "neorocks", + "neovim-nightly", "nixpkgs" ] }, "locked": { - "dir": "contrib", - "lastModified": 1704031853, - "narHash": "sha256-DOxfnhrIdTDWb+b9vKiuXq7zGTIhzC4g0EEP1uh36xs=", + "lastModified": 1719226092, + "narHash": "sha256-YNkUMcCUCpnULp40g+svYsaH1RbSEj6s4WdZY/SHe38=", + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "rev": "11e4b8dc112e2f485d7c97e1cee77f9958f498f5", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "type": "github" + } + }, + "neorocks": { + "inputs": { + "flake-compat": "flake-compat", + "flake-parts": "flake-parts_3", + "git-hooks": "git-hooks", + "neovim-nightly": "neovim-nightly", + "nixpkgs": "nixpkgs_4" + }, + "locked": { + "lastModified": 1721193886, + "narHash": "sha256-pjLc7CavrqEsxWmyNdp7SLSbFoAyPAHBPqw6/8U9Ixs=", + "owner": "nvim-neorocks", + "repo": "neorocks", + "rev": "f3b6b979cd746e73ed4cc2276830da1d2e076ffc", + "type": "github" + }, + "original": { + "owner": "nvim-neorocks", + "repo": "neorocks", + "type": "github" + } + }, + "neovim-nightly": { + "inputs": { + "flake-compat": "flake-compat_3", + "flake-parts": "flake-parts_4", + "git-hooks": "git-hooks_2", + "hercules-ci-effects": "hercules-ci-effects", + "neovim-src": "neovim-src", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1721175028, + "narHash": "sha256-3iNMy+GUVaFVHv2U+g6cMJwouAJinDkT/TLqZpiwsU8=", + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "rev": "d0040404432ef2f6492d06284c556303262e5054", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "type": "github" + } + }, + "neovim-src": { + "flake": false, + "locked": { + "lastModified": 1721152134, + "narHash": "sha256-mKvJmYNz0d+irdQFtUrkFtHY6LgE1SxoT14Zmbn1OXU=", "owner": "neovim", "repo": "neovim", - "rev": "6fa0f303d7f0823bfc5ba6cc7b4e7a7cd76143ac", + "rev": "1f2f460b4a77a8ff58872e03c071b5d0d882dd44", "type": "github" }, "original": { - "dir": "contrib", "owner": "neovim", "repo": "neovim", "type": "github" @@ -132,150 +399,183 @@ }, "nixpkgs": { "locked": { - "lastModified": 1703499205, - "narHash": "sha256-lF9rK5mSUfIZJgZxC3ge40tp1gmyyOXZ+lRY3P8bfbg=", + "lastModified": 1718714799, + "narHash": "sha256-FUZpz9rg3gL8NVPKbqU8ei1VkPLsTIfAJ2fdAf5qjak=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870", + "rev": "c00d587b1a1afbf200b1d8f0b0e4ba9deb1c7f0e", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixpkgs-unstable", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-lib": { "locked": { - "dir": "lib", - "lastModified": 1701253981, - "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", + "lastModified": 1719876945, + "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + } + }, + "nixpkgs-lib_2": { + "locked": { + "lastModified": 1717284937, + "narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" + } + }, + "nixpkgs-lib_3": { + "locked": { + "lastModified": 1719876945, + "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", "type": "github" }, "original": { - "dir": "lib", "owner": "NixOS", - "ref": "nixos-unstable", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-stable": { + "nixpkgs-stable_2": { "locked": { - "lastModified": 1685801374, - "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.05", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } }, - "plenary-nvim": { - "flake": false, + "nixpkgs_2": { "locked": { - "lastModified": 1701343040, - "narHash": "sha256-f8YVaXMG0ZyW6iotAgnftaYULnL69UPolRad6RTG27g=", - "owner": "nvim-lua", - "repo": "plenary.nvim", - "rev": "55d9fe89e33efd26f532ef20223e5f9430c8b0c0", + "lastModified": 1719082008, + "narHash": "sha256-jHJSUH619zBQ6WdC21fFAlDxHErKVDJ5fpN0Hgx4sjs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9693852a2070b398ee123a329e68f0dab5526681", "type": "github" }, "original": { - "owner": "nvim-lua", - "repo": "plenary.nvim", + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", "type": "github" } }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "flake-utils": "flake-utils_2", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, + "nixpkgs_3": { "locked": { - "lastModified": 1703426812, - "narHash": "sha256-aODSOH8Og8ne4JylPJn+hZ6lyv6K7vE5jFo4KAGIebM=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "7f35ec30d16b38fe0eed8005933f418d1a4693ee", + "lastModified": 1721116560, + "narHash": "sha256-++TYlGMAJM1Q+0nMVaWBSEvEUjRs7ZGiNQOpqbQApCU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9355fa86e6f27422963132c2c9aeedb0fb963d93", "type": "github" }, "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", "type": "github" } }, - "root": { - "inputs": { - "flake-parts": "flake-parts", - "neodev-nvim": "neodev-nvim", - "neovim": "neovim", - "nixpkgs": "nixpkgs", - "plenary-nvim": "plenary-nvim", - "pre-commit-hooks": "pre-commit-hooks", - "telescope-nvim": "telescope-nvim" - } - }, - "systems": { + "nixpkgs_4": { "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "lastModified": 1721116560, + "narHash": "sha256-++TYlGMAJM1Q+0nMVaWBSEvEUjRs7ZGiNQOpqbQApCU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9355fa86e6f27422963132c2c9aeedb0fb963d93", "type": "github" }, "original": { - "owner": "nix-systems", - "repo": "default", + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", "type": "github" } }, - "systems_2": { + "nixpkgs_5": { "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "lastModified": 1721116560, + "narHash": "sha256-++TYlGMAJM1Q+0nMVaWBSEvEUjRs7ZGiNQOpqbQApCU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9355fa86e6f27422963132c2c9aeedb0fb963d93", "type": "github" }, "original": { - "owner": "nix-systems", - "repo": "default", + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", "type": "github" } }, - "telescope-nvim": { - "flake": false, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat_5", + "gitignore": "gitignore_3", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_2" + }, "locked": { - "lastModified": 1703697665, - "narHash": "sha256-HnRjfgJZ6DUcf79eibpmKNNsP8DMSPczD06ZoXiOtHk=", - "owner": "nvim-telescope", - "repo": "telescope.nvim", - "rev": "e0651458f2ced647f3ff3c89d5663244b3cf45af", + "lastModified": 1721042469, + "narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "f451c19376071a90d8c58ab1a953c6e9840527fd", "type": "github" }, "original": { - "owner": "nvim-telescope", - "repo": "telescope.nvim", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", "type": "github" } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "gen-luarc": "gen-luarc", + "neorocks": "neorocks", + "nixpkgs": "nixpkgs_5", + "pre-commit-hooks": "pre-commit-hooks" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 636c1d7..88b1bc6 100644 --- a/flake.nix +++ b/flake.nix @@ -2,29 +2,33 @@ description = "git-worktree.nvim - supercharge your haskell experience in neovim"; inputs = { - flake-parts.url = "github:hercules-ci/flake-parts"; nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + pre-commit-hooks = { url = "github:cachix/pre-commit-hooks.nix"; inputs.nixpkgs.follows = "nixpkgs"; }; - neovim = { - url = "github:neovim/neovim?dir=contrib"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - neodev-nvim = { - url = "github:folke/neodev.nvim"; - flake = false; - }; - plenary-nvim = { - url = "github:nvim-lua/plenary.nvim"; - flake = false; - }; - telescope-nvim = { - url = "github:nvim-telescope/telescope.nvim"; - flake = false; - }; + neorocks.url = "github:nvim-neorocks/neorocks"; + gen-luarc.url = "github:mrcjkb/nix-gen-luarc-json"; + + # neovim = { + # url = "github:neovim/neovim?dir=contrib"; + # inputs.nixpkgs.follows = "nixpkgs"; + # }; + # neodev-nvim = { + # url = "github:folke/neodev.nvim"; + # flake = false; + # }; + # plenary-nvim = { + # url = "github:nvim-lua/plenary.nvim"; + # flake = false; + # }; + # telescope-nvim = { + # url = "github:nvim-telescope/telescope.nvim"; + # flake = false; + # }; }; outputs = inputs @ { @@ -46,6 +50,26 @@ inputs', ... }: let + luarc-plugins = with pkgs.lua51Packages; (with pkgs.vimPlugins; [ + telescope-nvim + plenary-nvim + ]); + + luarc-nightly = pkgs.mk-luarc { + nvim = pkgs.neovim-nightly; + plugins = luarc-plugins; + }; + + luarc-stable = pkgs.mk-luarc { + nvim = pkgs.neovim-unwrapped; + plugins = luarc-plugins; + disabled-diagnostics = [ + #"undefined-doc-name" + #"redundant-parameter" + #"invisible" + ]; + }; + pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { src = self; hooks = { @@ -59,8 +83,10 @@ _module.args.pkgs = import inputs.nixpkgs { inherit system; overlays = [ + inputs.neorocks.overlays.default + inputs.gen-luarc.overlays.default (final: _: { - neovim-nightly = inputs.neovim.packages.${final.system}.neovim; + # neovim-nightly = inputs.neovim.packages.${final.system}.neovim; }) ]; }; @@ -74,7 +100,6 @@ ]); in pkgs.mkShell { - name = "git-worktree-nvim"; buildInputs = [ luaEnv ]; @@ -96,39 +121,65 @@ ''; }; in { - default = mkDevShell "jit"; - luajit = mkDevShell "jit"; - lua-51 = mkDevShell "5_1"; - lua-52 = mkDevShell "5_2"; + default = let + in + pkgs.mkShell { + name = "git-worktree-nvim-shell"; + shellHook = '' + ${pre-commit-check.shellHook} + ln -fs ${pkgs.luarc-to-json luarc-nightly} .luarc.json + ''; + buildInputs = + self.checks.${system}.pre-commit-check.enabledPackages + ++ (with pkgs; [ + lua-language-server + busted-nlua + (lua5_1.withPackages (ps: + with ps; [ + luarocks + plenary-nvim + ])) + ]); + }; }; - packages.neodev-plugin = pkgs.vimUtils.buildVimPlugin { - name = "neodev.nvim"; - src = inputs.neodev-nvim; - }; - packages.plenary-plugin = pkgs.vimUtils.buildVimPlugin { - name = "plenary.nvim"; - src = inputs.plenary-nvim; - }; - packages.telescope-plugin = pkgs.vimUtils.buildVimPlugin { - name = "telescope.nvim"; - src = inputs.telescope-nvim; - }; + # packages.neodev-plugin = pkgs.vimUtils.buildVimPlugin { + # name = "neodev.nvim"; + # src = inputs.neodev-nvim; + # }; + # packages.plenary-plugin = pkgs.vimUtils.buildVimPlugin { + # name = "plenary.nvim"; + # src = inputs.plenary-nvim; + # }; + # packages.telescope-plugin = pkgs.vimUtils.buildVimPlugin { + # name = "telescope.nvim"; + # src = inputs.telescope-nvim; + # }; - checks = { - inherit pre-commit-check; - type-check-stable = pkgs.callPackage ./nix/type-check.nix { - stable = true; - inherit (config.packages) neodev-plugin telescope-plugin; - inherit (inputs) pre-commit-hooks; - inherit self; + checks = let + type-check-stable = inputs.pre-commit-hooks.lib.${system}.run { + src = self; + hooks = { + lua-ls = { + enable = true; + settings.configuration = luarc-stable; + }; + }; }; - type-check-nightly = pkgs.callPackage ./nix/type-check.nix { - stable = false; - inherit (config.packages) neodev-plugin telescope-plugin; - inherit (inputs) pre-commit-hooks; - inherit self; + + type-check-nightly = inputs.pre-commit-hooks.lib.${system}.run { + src = self; + hooks = { + lua-ls = { + enable = true; + settings.configuration = luarc-nightly; + }; + }; }; + in { + inherit pre-commit-check; + inherit type-check-stable; + inherit type-check-nightly; }; }; }; diff --git a/lua/git-worktree/config.lua b/lua/git-worktree/config.lua index a7f9a99..92807ab 100644 --- a/lua/git-worktree/config.lua +++ b/lua/git-worktree/config.lua @@ -1,7 +1,24 @@ -local M = {} +---@mod git-worktree.config + +---@brief [[ + +--- The plugin configuration. +--- Merges the default config with `vim.g.git_worktree`. + +---@brief ]] ---@class GitWorktreeConfig -local config = { +---@field change_directory_command string command to change directory on your OS +---@field update_on_change boolean ???? +---@field update_on_change_command string ????? +---@field clearjumps_on_change boolean +---@field confirm_telescope_deletions boolean +---@field autopush boolean + +---@type (fun():GitWorktreeConfig) | GitWorktreeConfig | nil +vim.g.haskell_tools = vim.g.haskell_tools + +local GitWorktreeDefaultConfig = { -- command to change directory on your OS. -- @@ -34,21 +51,10 @@ local config = { autopush = false, } ---- Get a configuration value ---- @param opt string ---- @return any -M.get = function() - return config -end - ---- Set user configurations ---- @param user_configs table ---- @return table -M.set = function(user_configs) - vim.validate { user_configs = { user_configs, 'table' } } +local git_worktree = vim.g.git_worktree or {} +---@type GitWorktreeConfig +local opts = type(git_worktree) == 'function' and git_worktree() or git_worktree - config = vim.tbl_deep_extend('force', config, user_configs) - return config -end +local GitWorktreeConfig = vim.tbl_deep_extend('force', {}, GitWorktreeDefaultConfig, opts) -return M +return GitWorktreeConfig diff --git a/lua/git-worktree/git.lua b/lua/git-worktree/git.lua index adc9474..c161fad 100644 --- a/lua/git-worktree/git.lua +++ b/lua/git-worktree/git.lua @@ -20,9 +20,8 @@ function M.has_worktree(path_str, cb) end local job = Job:new { - 'git', - 'worktree', - 'list', + command = 'git', + args = { 'worktree', 'list' }, on_stdout = function(_, data) local list_data = {} for section in data:gmatch('%S+') do @@ -60,10 +59,8 @@ end --- @return string|nil function M.gitroot_dir() local job = Job:new { - 'git', - 'rev-parse', - '--path-format=absolute', - '--git-common-dir', + command = 'git', + args = { 'rev-parse', '--path-format=absolute', '--git-common-dir' }, cwd = vim.loop.cwd(), on_stderr = function(_, data) Log.error('ERROR: ' .. data) @@ -88,10 +85,8 @@ end --- @return string|nil function M.toplevel_dir() local job = Job:new { - 'git', - 'rev-parse', - '--path-format=absolute', - '--show-toplevel', + command = 'git', + args = { 'rev-parse', '--path-format=absolute', '--show-toplevel' }, cwd = vim.loop.cwd(), on_stderr = function(_, data) Log.error('ERROR: ' .. data) @@ -116,8 +111,8 @@ end function M.has_branch(branch, cb) local found = false local job = Job:new { - 'git', - 'branch', + command = 'git', + args = { 'branch' }, on_stdout = function(_, data) -- remove markere on current branch data = data:gsub('*', '') @@ -182,12 +177,11 @@ function M.delete_worktree_job(path, force) end --- @param path string ---- @return plenary:Job +--- @return Job function M.fetchall_job(path) return Job:new { - 'git', - 'fetch', - '--all', + command = 'git', + args = { 'fetch', '--all' }, cwd = path, on_start = function() Log.debug('git fetch --all (This may take a moment)') @@ -198,7 +192,7 @@ end --- @param path string --- @param branch string --- @param upstream string ---- @return plenary:Job +--- @return Job function M.setbranch_job(path, branch, upstream) local set_branch_cmd = 'git' local set_branch_args = { 'branch', string.format('--set-upstream-to=%s/%s', upstream, branch) } @@ -215,7 +209,7 @@ end --- @param path string --- @param branch string --- @param upstream string ---- @return plenary:Job +--- @return Job function M.setpush_job(path, branch, upstream) -- TODO: How to configure origin??? Should upstream ever be the push -- destination? @@ -232,11 +226,11 @@ function M.setpush_job(path, branch, upstream) end --- @param path string ---- @return plenary:Job +--- @return Job function M.rebase_job(path) return Job:new { - 'git', - 'rebase', + command = 'git', + args = { 'rebase' }, cwd = path, on_start = function() Log.debug('git rebase') diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index 9f9f551..f46ab6a 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -1,92 +1,98 @@ -local Path = require('plenary.path') - ---- @class GitWorkTreeHook ---- @field SWITCH? fun(...): nil ---- @field CREATE? fun(...): nil ---- @field DELETE? fun(...): nil - local M = {} -local Hooks = {} - -Hooks.__index = Hooks - -function Hooks:new() - return setmetatable({ - hooks = {}, - }, self) -end - ----@param hook GitWorktreeHook -function Hooks:add_listener(hook) - table.insert(self.hooks, hook) -end +---@enum git-worktree.hooks.type +M.type = { + CREATE = 'CREATE', + DELETE = 'DELETE', + SWITCH = 'SWITCH', +} -function M:clear_listeners() - self.hooks = {} +local hooks = { + [M.type.CREATE] = {}, + [M.type.DELETE] = {}, + [M.type.SWITCH] = {}, +} +local count = 0 + +---@alias git-worktree.hooks.cb.create fun(bufnr: number) +---@alias git-worktree.hooks.cb.delete fun(bufnr: number) +---@alias git-worktree.hooks.cb.switch fun(tick: number, bufnr: number, row: number, line: string) + +--- Registers a hook +--- +--- Each hook type takes a callback a different function, and a configuration table +---@param type git-worktree.hooks.type +---@param cb function +---@overload fun(type: 'CREATE', cb: git-worktree.hooks.cb.create): string +---@overload fun(type: 'DELETE', cb: git-worktree.hooks.cb.delete): string +---@overload fun(type: 'SWITCH', cb: git-worktree.hooks.cb.switch): string +M.register = function(type, cb) + count = count + 1 + local hook_id = type .. '_' .. tostring(count) + hooks[type][hook_id] = cb + return hook_id end ---@param type string ---@param ... any -function Hooks:emit(type, ...) - print('emitting') - for _, cb in ipairs(self.hooks) do - print(type) - if cb[type] then - print(vim.inspect(cb)) - cb[type](...) - end +function M.emit(type, ...) + for _, hook in pairs(hooks[type]) do + hook(...) end end -local builtins = {} - -builtins.update_current_buffer_on_switch = function(_, prev_path) - if prev_path == nil then - local config = require('git-worktree.config').get() - vim.cmd(config.update_on_change_command) - end - - local cwd = vim.loop.cwd() - local current_buf_name = vim.api.nvim_buf_get_name(0) - if not current_buf_name or current_buf_name == '' then - local config = require('git-worktree.config').get() - vim.cmd(config.update_on_change_command) - end - - local name = Path:new(current_buf_name):absolute() - local start1, _ = string.find(name, cwd .. Path.path.sep, 1, true) - if start1 ~= nil then - return - end +local Path = require('plenary.path') - local start, fin = string.find(name, prev_path, 1, true) - if start == nil then - local config = require('git-worktree.config').get() - vim.cmd(config.update_on_change_command) - end +--- Built in hooks +--- +--- You can register them yourself using `hooks.register` +--- +--- +--- hooks.register( +--- hooks.type.SKIP_LINE, +--- hooks.builtin.skip_preproc_lines, +--- { bufnr = 0 } +--- ) +--- +M.builtins = { + ---@type git-worktree.hooks.cb.switch + update_current_buffer_on_switch = function(_, prev_path) + if prev_path == nil then + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) + end - local local_name = name:sub(fin + 2) + local cwd = vim.loop.cwd() + local current_buf_name = vim.api.nvim_buf_get_name(0) + if not current_buf_name or current_buf_name == '' then + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) + end - local final_path = Path:new({ cwd, local_name }):absolute() + local name = Path:new(current_buf_name):absolute() + local start1, _ = string.find(name, cwd .. Path.path.sep, 1, true) + if start1 ~= nil then + return + end - if not Path:new(final_path):exists() then - local config = require('git-worktree.config').get() - vim.cmd(config.update_on_change_command) - end + local start, fin = string.find(name, prev_path, 1, true) + if start == nil then + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) + end - local bufnr = vim.fn.bufnr(final_path, true) - vim.api.nvim_set_current_buf(bufnr) -end + local local_name = name:sub(fin + 2) -M.hooks = Hooks:new() + local final_path = Path:new({ cwd, local_name }):absolute() -M.builtins = builtins + if not Path:new(final_path):exists() then + local config = require('git-worktree.config').get() + vim.cmd(config.update_on_change_command) + end -M.hook_event_names = { - CREATE = 'CREATE', - DELETE = 'DELETE', - SWITCH = 'SWITCH', + local bufnr = vim.fn.bufnr(final_path, true) + vim.api.nvim_set_current_buf(bufnr) + end, } return M diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index ce3a121..2c942f2 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -1,14 +1,7 @@ -local Config = require('git-worktree.config') local Worktree = require('git-worktree.worktree') local M = {} -function M.setup(user_configs) - Config.set(user_configs or {}) - -- initialize hooks - require('git-worktree.hooks') -end - --Switch the current worktree ---@param path string -- luacheck:ignore self diff --git a/lua/git-worktree/setup_spec.lua b/lua/git-worktree/setup_spec.lua deleted file mode 100644 index 34d7867..0000000 --- a/lua/git-worktree/setup_spec.lua +++ /dev/null @@ -1,5 +0,0 @@ -describe('Can require haskell-tools with default configs.', function() - it('Public API is available after setup.', function() - assert(1 == 1) - end) -end) diff --git a/lua/git-worktree/worktree.lua b/lua/git-worktree/worktree.lua index 4c2fadd..4db00e6 100644 --- a/lua/git-worktree/worktree.lua +++ b/lua/git-worktree/worktree.lua @@ -7,6 +7,9 @@ local function get_absolute_path(path) if Path:new(path):is_absolute() then return path else + print(path) + print(vim.loop.cwd()) + print(Path:new(vim.loop.cwd(), path)) return Path:new(vim.loop.cwd(), path):absolute() end end @@ -15,7 +18,7 @@ local function change_dirs(path) Log.info('changing dirs: %s ', path) local worktree_path = get_absolute_path(path) local previous_worktree = vim.loop.cwd() - local config = require('git-worktree.config').get() + local config = require('git-worktree.config') -- vim.loop.chdir(worktree_path) if Path:new(worktree_path):exists() then @@ -70,7 +73,7 @@ function M.switch(path) vim.schedule(function() local prev_path = change_dirs(path) local Hooks = require('git-worktree.hooks') - Hooks.hooks:emit(Hooks.hook_event_names.SWITCH, path, prev_path) + Hooks.emit(Hooks.type.SWITCH, path, prev_path) end) end) end @@ -97,7 +100,7 @@ function M.create(path, branch, upstream) end Git.has_branch(branch, function(found_branch) - local config = require('git-worktree.config').get() + local config = require('git-worktree.config') local worktree_path if Path:new(path):is_absolute() then worktree_path = path @@ -139,7 +142,7 @@ function M.create(path, branch, upstream) vim.schedule(function() local Hooks = require('git-worktree.hooks') - Hooks.hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) + Hooks.emit(Hooks.type.CREATE, path, branch, upstream) M.switch(path) end) end) @@ -147,7 +150,7 @@ function M.create(path, branch, upstream) create_wt_job:after(function() vim.schedule(function() local Hooks = require('git-worktree.hooks') - Hooks.hooks:emit(Hooks.hook_event_names.CREATE, path, branch, upstream) + Hooks.emit(Hooks.type.CREATE, path, branch, upstream) M.switch(path) end) end) @@ -180,7 +183,7 @@ function M.delete(path, force, opts) delete:after_success(vim.schedule_wrap(function() Log.info('delete after success') local Hooks = require('git-worktree.hooks') - Hooks.hooks:emit(Hooks.hook_event_names.DELETE, path) + Hooks.emit(Hooks.type.DELETE, path) if opts.on_success then opts.on_success() end diff --git a/lua/telescope/_extensions/git_worktree.lua b/lua/telescope/_extensions/git_worktree.lua index 26aecef..d3e2137 100644 --- a/lua/telescope/_extensions/git_worktree.lua +++ b/lua/telescope/_extensions/git_worktree.lua @@ -10,39 +10,54 @@ local git_worktree = require('git-worktree') local force_next_deletion = false +-- Get the path of the selected worktree +-- @param prompt_bufnr number: the prompt buffer number +-- @return string: the path of the selected worktree local get_worktree_path = function(prompt_bufnr) local selection = action_state.get_selected_entry(prompt_bufnr) return selection.path end +-- Switch to the selected worktree +-- @param prompt_bufnr number: the prompt buffer number +-- @return nil local switch_worktree = function(prompt_bufnr) local worktree_path = get_worktree_path(prompt_bufnr) actions.close(prompt_bufnr) if worktree_path ~= nil then - git_worktree:switch_worktree(worktree_path) + git_worktree.switch_worktree(worktree_path) end end +-- Toggle the forced deletion of the next worktree +-- @return nil local toggle_forced_deletion = function() -- redraw otherwise the message is not displayed when in insert mode if force_next_deletion then - -- print('The next deletion will not be forced') + vim.print('The next deletion will not be forced') vim.fn.execute('redraw') else - -- print('The next deletion will be forced') + vim.print('The next deletion will be forced') vim.fn.execute('redraw') force_next_deletion = true end end +-- Handler for successful deletion +-- @return nil local delete_success_handler = function() force_next_deletion = false end +-- Handler for failed deletion +-- @return nil local delete_failure_handler = function() - -- print('Deletion failed, use to force the next deletion') + print('Deletion failed, use to force the next deletion') end +-- Ask the user to confirm the deletion of a worktree +-- @param forcing boolean: whether the deletion is forced +-- @return boolean: whether the deletion is confirmed local ask_to_confirm_deletion = function(forcing) if forcing then return vim.fn.input('Force deletion of worktree? [y/n]: ') @@ -51,6 +66,9 @@ local ask_to_confirm_deletion = function(forcing) return vim.fn.input('Delete worktree? [y/n]: ') end +-- Confirm the deletion of a worktree +-- @param forcing boolean: whether the deletion is forced +-- @return boolean: whether the deletion is confirmed local confirm_deletion = function(forcing) if not git_worktree._config.confirm_telescope_deletions then return true @@ -62,10 +80,13 @@ local confirm_deletion = function(forcing) return true end - -- print("Didn't delete worktree") + print("Didn't delete worktree") return false end +-- Delete the selected worktree +-- @param prompt_bufnr number: the prompt buffer number +-- @return nil local delete_worktree = function(prompt_bufnr) if not confirm_deletion() then return @@ -81,6 +102,48 @@ local delete_worktree = function(prompt_bufnr) end end +-- Create a prompt to get the path of the new worktree +-- @param cb function: the callback to call with the path +-- @return nil +local create_input_prompt = function(cb) + local subtree = vim.fn.input('Path to subtree > ') + cb(subtree) +end + +-- Create a worktree +-- @param opts table: the options for the telescope picker (optional) +-- @return nil +local create_worktree = function(opts) + opts = opts or {} + opts.attach_mappings = function() + actions.select_default:replace(function(prompt_bufnr, _) + local selected_entry = action_state.get_selected_entry() + local current_line = action_state.get_current_line() + + actions.close(prompt_bufnr) + + local branch = selected_entry ~= nil and selected_entry.value or current_line + + if branch == nil then + return + end + + create_input_prompt(function(name) + if name == '' then + name = branch + end + git_worktree.create_worktree(name, branch) + end) + end) + + return true + end + require('telescope.builtin').git_branches(opts) +end + +-- List the git worktrees +-- @param opts table: the options for the telescope picker (optional) +-- @return nil local telescope_git_worktree = function(opts) opts = opts or {} local output = utils.get_os_command_output { 'git', 'worktree', 'list' } @@ -103,8 +166,7 @@ local telescope_git_worktree = function(opts) local index = #results + 1 for key, val in pairs(widths) do if key == 'path' then - local new_path = utils.transform_path(opts, entry[key]) - local path_len = strings.strdisplaywidth(new_path or '') + local path_len = strings.strdisplaywidth(entry[key] or '') widths[key] = math.max(val, path_len) else widths[key] = math.max(val, strings.strdisplaywidth(entry[key] or '')) @@ -167,41 +229,8 @@ local telescope_git_worktree = function(opts) :find() end -local create_input_prompt = function(cb) - local subtree = vim.fn.input('Path to subtree > ') - cb(subtree) -end - -local create_worktree = function(opts) - opts = opts or {} - opts.attach_mappings = function() - actions.select_default:replace(function(prompt_bufnr, _) - local selected_entry = action_state.get_selected_entry() - local current_line = action_state.get_current_line() - - actions.close(prompt_bufnr) - - local branch = selected_entry ~= nil and selected_entry.value or current_line - - if branch == nil then - return - end - - create_input_prompt(function(name) - if name == '' then - name = branch - end - git_worktree.create_worktree(name, branch) - end) - end) - - -- do we need to replace other default maps? - - return true - end - require('telescope.builtin').git_branches(opts) -end - +-- Register the extension +-- @return table: the extension return require('telescope').register_extension { exports = { git_worktree = telescope_git_worktree, diff --git a/nix/type-check.nix b/nix/type-check.nix deleted file mode 100644 index 85f01e4..0000000 --- a/nix/type-check.nix +++ /dev/null @@ -1,68 +0,0 @@ -{ - stable ? true, - self, - system, - neodev-plugin, - neovim, - neovim-nightly, - pre-commit-hooks, - telescope-plugin, -}: let - mkTypeCheck = { - nvim-api ? [], - disabled-diagnostics ? [], - }: - pre-commit-hooks.lib.${system}.run { - src = self; - hooks = { - lua-ls.enable = true; - }; - settings = { - lua-ls = { - config = { - runtime.version = "LuaJIT"; - Lua = { - workspace = { - library = - nvim-api - ++ [ - "${telescope-plugin}/lua" - ]; - checkThirdParty = false; - ignoreDir = [ - ".git" - ".github" - ".direnv" - "result" - "nix" - "doc" - "spec" - ]; - }; - diagnostics = { - libraryFiles = "Disable"; - disable = disabled-diagnostics; - }; - }; - }; - }; - }; - }; -in - mkTypeCheck { - nvim-api = - if stable - then [ - "${neovim}/share/nvim/runtime/lua" - "${neodev-plugin}/types/stable" - ] - else [ - "${neovim-nightly}/share/nvim/runtime/lua" - "${neodev-plugin}/types/nightly" - ]; - disabled-diagnostics = [ - "undefined-doc-name" - "redundant-parameter" - "invisible" - ]; - } diff --git a/plugin/git-worktree.lua b/plugin/git-worktree.lua deleted file mode 100644 index a618700..0000000 --- a/plugin/git-worktree.lua +++ /dev/null @@ -1,8 +0,0 @@ -if not vim.g.did_gitworktree_initialize then - vim.api.nvim_create_user_command('GitWorktreeSwitch', function(args) - local path = args['args'] - require('git-worktree').switch_worktree(path) - end, { desc = 'Switch to worktree', nargs = 1 }) -end - -vim.g.did_gitworktree_initialize = true diff --git a/lua/git-worktree/config_spec.lua b/spec/config_spec.lua similarity index 72% rename from lua/git-worktree/config_spec.lua rename to spec/config_spec.lua index 6d7b70c..b6171f8 100644 --- a/lua/git-worktree/config_spec.lua +++ b/spec/config_spec.lua @@ -6,12 +6,12 @@ describe('config', function() local config = require('git-worktree.config') it('returns the default config', function() - assert.truthy(config.get().change_directory_command) + assert.truthy(config.change_directory_command) end) it('can have configuration applied', function() - config.set { change_directory_command = 'test' } - assert.equals(config.get().change_directory_command, 'test') + config.change_directory_command = 'test' + assert.equals(config.change_directory_command, 'test') end) it('No notifications at startup.', function() diff --git a/lua/git-worktree/git_spec.lua b/spec/git_spec.lua similarity index 100% rename from lua/git-worktree/git_spec.lua rename to spec/git_spec.lua diff --git a/lua/git-worktree/worktree_spec.lua b/spec/worktree_spec.lua similarity index 63% rename from lua/git-worktree/worktree_spec.lua rename to spec/worktree_spec.lua index e1f9abc..504ad5d 100644 --- a/lua/git-worktree/worktree_spec.lua +++ b/spec/worktree_spec.lua @@ -1,17 +1,34 @@ local git_harness = require('git-worktree.test.git_util') +local Hooks = require('git-worktree.hooks') local Path = require('plenary.path') -local stub = require('luassert.stub') local cwd = vim.fn.getcwd() -- luacheck: globals repo_dir config git_worktree describe('[Worktree]', function() - local Hooks = require('git-worktree.hooks').hooks - stub(Hooks, 'emit') + local completed_create = false + local completed_switch = false + local completed_delete = false + + local reset_variables = function() + completed_create = false + completed_switch = false + completed_delete = false + end + + Hooks.register(Hooks.type.CREATE, function() + completed_create = true + end) + Hooks.register(Hooks.type.DELETE, function() + completed_delete = true + end) + Hooks.register(Hooks.type.SWITCH, function() + completed_switch = true + end) before_each(function() + reset_variables() git_worktree = require('git-worktree') - git_worktree.setup {} end) after_each(function() vim.api.nvim_command('cd ' .. cwd) @@ -27,18 +44,13 @@ describe('[Worktree]', function() local wt = 'featB' local input_path = '../' .. wt local expected_path = working_dir .. Path.path.sep .. wt - local prev_path = working_dir .. Path.path.sep .. 'master' + -- local prev_path = working_dir .. Path.path.sep .. 'master' require('git-worktree').switch_worktree(input_path) - local co = coroutine.running() - vim.defer_fn(function() - coroutine.resume(co) + vim.fn.wait(10000, function() + return completed_switch end, 1000) - --The test will reach here immediately. - coroutine.yield() - -- Check to make sure directory was switched - assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) assert.are.same(expected_path, vim.loop.cwd()) end) end) @@ -51,18 +63,14 @@ describe('[Worktree]', function() local wt = 'featB' local input_path = '../' .. wt local expected_path = working_dir .. Path.path.sep .. wt - local prev_path = working_dir .. Path.path.sep .. 'master' + -- local prev_path = working_dir .. Path.path.sep .. 'master' require('git-worktree').switch_worktree(input_path) - local co = coroutine.running() - vim.defer_fn(function() - coroutine.resume(co) + vim.fn.wait(10000, function() + return completed_switch end, 1000) - --The test will reach here immediately. - coroutine.yield() -- Check to make sure directory was switched - assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) assert.are.same(expected_path, vim.loop.cwd()) end) end) @@ -78,19 +86,14 @@ describe('[Worktree]', function() local wt = 'featB' local input_path = '../' .. wt local expected_path = working_dir .. Path.path.sep .. wt - local prev_path = working_dir .. Path.path.sep .. 'master' + -- local prev_path = working_dir .. Path.path.sep .. 'master' require('git-worktree').create_worktree(input_path, wt) - local co = coroutine.running() - vim.defer_fn(function() - coroutine.resume(co) + vim.fn.wait(10000, function() + return completed_create and completed_switch end, 1000) - --The test will reach here immediately. - coroutine.yield() -- Check to make sure directory was switched - assert.stub(Hooks.emit).was_called_with(Hooks, 'CREATE', input_path, wt, nil) - assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) assert.are.same(expected_path, vim.loop.cwd()) end) end) @@ -102,19 +105,14 @@ describe('[Worktree]', function() local wt = 'featB' local input_path = '../' .. wt local expected_path = working_dir .. Path.path.sep .. wt - local prev_path = working_dir .. Path.path.sep .. 'master' + -- local prev_path = working_dir .. Path.path.sep .. 'master' require('git-worktree').create_worktree(input_path, wt) - local co = coroutine.running() - vim.defer_fn(function() - coroutine.resume(co) + vim.fn.wait(10000, function() + return completed_create and completed_switch end, 1000) - --The test will reach here immediately. - coroutine.yield() -- Check to make sure directory was switched - assert.stub(Hooks.emit).was_called_with(Hooks, 'CREATE', input_path, wt, nil) - assert.stub(Hooks.emit).was_called_with(Hooks, 'SWITCH', input_path, prev_path) assert.are.same(expected_path, vim.loop.cwd()) end) end) @@ -131,15 +129,11 @@ describe('[Worktree]', function() local input_path = '../' .. wt require('git-worktree').delete_worktree(input_path, true) - local co = coroutine.running() - vim.defer_fn(function() - coroutine.resume(co) + vim.fn.wait(10000, function() + return completed_delete end, 1000) - --The test will reach here immediately. - coroutine.yield() -- Check to make sure directory was switched - assert.stub(Hooks.emit).was_called_with(Hooks, 'DELETE', input_path) assert.are.same(master_dir, vim.loop.cwd()) end) end) @@ -152,15 +146,11 @@ describe('[Worktree]', function() local input_path = '../' .. wt require('git-worktree').delete_worktree(input_path, wt) - local co = coroutine.running() - vim.defer_fn(function() - coroutine.resume(co) + vim.fn.wait(10000, function() + return completed_delete end, 1000) - --The test will reach here immediately. - coroutine.yield() -- Check to make sure directory was switched - assert.stub(Hooks.emit).was_called_with(Hooks, 'DELETE', input_path) assert.are.same(master_dir, vim.loop.cwd()) end) end) From 24381c89740fee1fda837113c487081cea37783b Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 09:15:35 -0400 Subject: [PATCH 26/33] docs: update plugin help docs --- doc/git-worktree.txt | 121 ++++++++++++++++++++++++++++++++++++ flake.nix | 5 ++ lua/git-worktree/config.lua | 52 +++++++++------- lua/git-worktree/hooks.lua | 18 +++--- lua/git-worktree/init.lua | 16 ++++- nix/docgen.nix | 11 ++++ 6 files changed, 191 insertions(+), 32 deletions(-) create mode 100644 nix/docgen.nix diff --git a/doc/git-worktree.txt b/doc/git-worktree.txt index e69de29..aa19cd5 100644 --- a/doc/git-worktree.txt +++ b/doc/git-worktree.txt @@ -0,0 +1,121 @@ +============================================================================== +Table of Contents *git-worktree.contents* + +Introduction ··························································· |intro| + ································································ |git-worktree| +plugin configuration ····································· |git-worktree.config| +hooks ····················································· |git-worktree.hooks| + +============================================================================== +Introduction *intro* + + A plugin that helps to use git worktree operations, create, switch, and delete in neovim. + +============================================================================== + *git-worktree* + + + +M.switch_worktree({path}) *M.switch_worktree* + + Parameters: ~ + {path} (string) + + + *M.create_worktree* +M.create_worktree({path}, {branch}, {upstream?}) + + Parameters: ~ + {path} (string) + {branch} (string) + {upstream?} (string) + + + *M.delete_worktree* +M.delete_worktree({path}, {force}, {opts}) + + Parameters: ~ + {path} (string) + {force} (boolean) + {opts} (any) + + +============================================================================== +plugin configuration *git-worktree.config* + + + git-worktree.nvim does not need a `setup` function to work. + +To configure git-worktree.nvim, set the variable `vim.g.git-worktree`, +which is a `GitWorktreeConfig` table, in your neovim configuration. + + The plugin configuration. + Merges the default config with `vim.g.git_worktree`. + +Example: + +>lua +---@type GitWorktreeConfig +vim.g.git_worktree = { + change_directory_command = 'cd', + update_on_change = true, + update_on_change_command = 'e .', + clearjumps_on_change = true, + confirm_telescope_deletions = true, + autopush = false, + } +< + + +GitWorktreeConfig *GitWorktreeConfig* + + Fields: ~ + {change_directory_command} (string) command to change directory on your OS + {update_on_change_command} (string) vim command to call to switch file buffer to new git-worktree + {clearjumps_on_change} (boolean) clear jump list on change + {confirm_telescope_deletions} (boolean) confirm telescope deletions operations + {autopush} (boolean) automatically push worktree to origin repo + + +============================================================================== +hooks *git-worktree.hooks* + +git-worktree.hooks.cb.create *git-worktree.hooks.cb.create* + + Type: ~ + fun(path:string,branch:string,upstream:string) + + +git-worktree.hooks.cb.delete *git-worktree.hooks.cb.delete* + + Type: ~ + fun(path:string) + + +git-worktree.hooks.cb.switch *git-worktree.hooks.cb.switch* + + Type: ~ + fun(path:string,prev_path:string) + + +M.register({type}, {cb}) *M.register* + Registers a hook + + Each hook type takes a callback a different function + + Parameters: ~ + {type} (git-worktree.hooks.type) + {cb} (function) @overload fun(type: 'CREATE', cb: git-worktree.hooks.cb.create): string + @overload fun(type: 'DELETE', cb: git-worktree.hooks.cb.delete): string + @overload fun(type: 'SWITCH', cb: git-worktree.hooks.cb.switch): string + + +M.emit({type}, {...}) *M.emit* + Emits an event and calls all the hook callbacks registered + + Parameters: ~ + {type} (git-worktree.hooks.type) + {...} (any) + + +vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/flake.nix b/flake.nix index 88b1bc6..3d0f3a9 100644 --- a/flake.nix +++ b/flake.nix @@ -143,6 +143,11 @@ }; }; + packages = let + docgen = pkgs.callPackage ./nix/docgen.nix {}; + in { + inherit docgen; + }; # packages.neodev-plugin = pkgs.vimUtils.buildVimPlugin { # name = "neodev.nvim"; # src = inputs.neodev-nvim; diff --git a/lua/git-worktree/config.lua b/lua/git-worktree/config.lua index 92807ab..d159229 100644 --- a/lua/git-worktree/config.lua +++ b/lua/git-worktree/config.lua @@ -1,52 +1,62 @@ ----@mod git-worktree.config - +---@mod git-worktree.config plugin configuration +--- ---@brief [[ +--- +--- git-worktree.nvim does not need a `setup` function to work. +--- +---To configure git-worktree.nvim, set the variable `vim.g.git-worktree`, +---which is a `GitWorktreeConfig` table, in your neovim configuration. +--- --- The plugin configuration. --- Merges the default config with `vim.g.git_worktree`. +--- +---Example: +--- +--->lua +------@type GitWorktreeConfig +---vim.g.git_worktree = { +--- change_directory_command = 'cd', +--- update_on_change = true, +--- update_on_change_command = 'e .', +--- clearjumps_on_change = true, +--- confirm_telescope_deletions = true, +--- autopush = false, +--- } +---< +--- ---@brief ]] ---@class GitWorktreeConfig ---@field change_directory_command string command to change directory on your OS ----@field update_on_change boolean ???? ----@field update_on_change_command string ????? ----@field clearjumps_on_change boolean ----@field confirm_telescope_deletions boolean ----@field autopush boolean +---@field update_on_change_command string vim command to call to switch file buffer to new git-worktree +---@field clearjumps_on_change boolean clear jump list on change +---@field confirm_telescope_deletions boolean confirm telescope deletions operations +---@field autopush boolean automatically push worktree to origin repo ---@type (fun():GitWorktreeConfig) | GitWorktreeConfig | nil -vim.g.haskell_tools = vim.g.haskell_tools +vim.g.git_worktree = vim.g.git_worktree local GitWorktreeDefaultConfig = { -- command to change directory on your OS. - -- --- @type string change_directory_command = 'cd', - -- ????? - -- - --- @type boolean - update_on_change = true, - - -- ???? - -- + -- vim command to call to switch file buffer to new git-worktree --- @type string update_on_change_command = 'e .', -- clear jump list on change - -- --- @type boolean clearjumps_on_change = true, - -- confirm telescope deletions - -- + -- confirm telescope deletions operations --- @type boolean confirm_telescope_deletions = true, - -- ???? autopush worktree to origin - -- + -- automatically push worktree to origin repo --- @type boolean autopush = false, } diff --git a/lua/git-worktree/hooks.lua b/lua/git-worktree/hooks.lua index f46ab6a..f1573e3 100644 --- a/lua/git-worktree/hooks.lua +++ b/lua/git-worktree/hooks.lua @@ -1,3 +1,5 @@ +---@mod git-worktree.hooks hooks + local M = {} ---@enum git-worktree.hooks.type @@ -14,13 +16,13 @@ local hooks = { } local count = 0 ----@alias git-worktree.hooks.cb.create fun(bufnr: number) ----@alias git-worktree.hooks.cb.delete fun(bufnr: number) ----@alias git-worktree.hooks.cb.switch fun(tick: number, bufnr: number, row: number, line: string) +---@alias git-worktree.hooks.cb.create fun(path: string, branch: string, upstream: string) +---@alias git-worktree.hooks.cb.delete fun(path: string) +---@alias git-worktree.hooks.cb.switch fun(path: string, prev_path: string) --- Registers a hook --- ---- Each hook type takes a callback a different function, and a configuration table +--- Each hook type takes a callback a different function ---@param type git-worktree.hooks.type ---@param cb function ---@overload fun(type: 'CREATE', cb: git-worktree.hooks.cb.create): string @@ -33,7 +35,8 @@ M.register = function(type, cb) return hook_id end ----@param type string +--- Emits an event and calls all the hook callbacks registered +---@param type git-worktree.hooks.type ---@param ... any function M.emit(type, ...) for _, hook in pairs(hooks[type]) do @@ -49,9 +52,8 @@ local Path = require('plenary.path') --- --- --- hooks.register( ---- hooks.type.SKIP_LINE, ---- hooks.builtin.skip_preproc_lines, ---- { bufnr = 0 } +--- hooks.type.SWTICH, +--- hooks.builtins.update_current_buffer_on_switch, --- ) --- M.builtins = { diff --git a/lua/git-worktree/init.lua b/lua/git-worktree/init.lua index 2c942f2..a4241ce 100644 --- a/lua/git-worktree/init.lua +++ b/lua/git-worktree/init.lua @@ -1,10 +1,21 @@ -local Worktree = require('git-worktree.worktree') +---@toc git-worktree.contents + +---@mod intro Introduction +---@brief [[ +--- A plugin that helps to use git worktree operations, create, switch, and delete in neovim. +---@brief ]] +--- +---@mod git-worktree + +---@brief [[ +---@brief ]] local M = {} +local Worktree = require('git-worktree.worktree') + --Switch the current worktree ---@param path string --- luacheck:ignore self function M.switch_worktree(path) Worktree.switch(path) end @@ -13,7 +24,6 @@ end ---@param path string ---@param branch string ---@param upstream? string --- luacheck:ignore self function M.create_worktree(path, branch, upstream) Worktree.create(path, branch, upstream) end diff --git a/nix/docgen.nix b/nix/docgen.nix new file mode 100644 index 0000000..9aca0a7 --- /dev/null +++ b/nix/docgen.nix @@ -0,0 +1,11 @@ +{pkgs, ...}: +pkgs.writeShellApplication { + name = "docgen"; + runtimeInputs = with pkgs; [ + lemmy-help + ]; + text = '' + mkdir -p doc + lemmy-help lua/git-worktree/{init,config,hooks}.lua > doc/git-worktree.txt + ''; +} From 53e0c3246295c123ba2ffa41830dda49d045e2fb Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 10:46:33 -0400 Subject: [PATCH 27/33] ci: add busted test to nix check --- flake.nix | 19 +++++++++++++++++++ lua/git-worktree/worktree.lua | 19 +++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/flake.nix b/flake.nix index 3d0f3a9..86c7a4d 100644 --- a/flake.nix +++ b/flake.nix @@ -181,10 +181,29 @@ }; }; }; + + neorocks-test = pkgs.neorocksTest { + src = self; # Project containing the rockspec and .busted files. + # Plugin name. If running multiple tests, + # you can use pname for the plugin name instead + name = "git-worktree.nvim"; + # version = "scm-1"; # Optional, defaults to "scm-1"; + neovim = pkgs.neovim-nightly; # Optional, defaults to neovim-nightly. + luaPackages = ps: + # Optional + with ps; [ + # LuaRocks dependencies must be added here. + plenary-nvim + ]; + extraPackages = with pkgs; [ + gitMinimal + ]; # Optional. External test runtime dependencies. + }; in { inherit pre-commit-check; inherit type-check-stable; inherit type-check-nightly; + inherit neorocks-test; }; }; }; diff --git a/lua/git-worktree/worktree.lua b/lua/git-worktree/worktree.lua index 4db00e6..4e85288 100644 --- a/lua/git-worktree/worktree.lua +++ b/lua/git-worktree/worktree.lua @@ -2,14 +2,13 @@ local Path = require('plenary.path') local Git = require('git-worktree.git') local Log = require('git-worktree.logger') +local Hooks = require('git-worktree.hooks') +local Config = require('git-worktree.config') local function get_absolute_path(path) if Path:new(path):is_absolute() then return path else - print(path) - print(vim.loop.cwd()) - print(Path:new(vim.loop.cwd(), path)) return Path:new(vim.loop.cwd(), path):absolute() end end @@ -18,18 +17,18 @@ local function change_dirs(path) Log.info('changing dirs: %s ', path) local worktree_path = get_absolute_path(path) local previous_worktree = vim.loop.cwd() - local config = require('git-worktree.config') + Config = require('git-worktree.config') -- vim.loop.chdir(worktree_path) if Path:new(worktree_path):exists() then - local cmd = string.format('%s %s', config.change_directory_command, worktree_path) + local cmd = string.format('%s %s', Config.change_directory_command, worktree_path) Log.debug('Changing to directory %s', worktree_path) vim.cmd(cmd) else Log.error('Could not chang to directory: %s', worktree_path) end - if config.clearjumps_on_change then + if Config.clearjumps_on_change then Log.debug('Clearing jumps') vim.cmd('clearjumps') end @@ -72,7 +71,6 @@ function M.switch(path) vim.schedule(function() local prev_path = change_dirs(path) - local Hooks = require('git-worktree.hooks') Hooks.emit(Hooks.type.SWITCH, path, prev_path) end) end) @@ -100,7 +98,7 @@ function M.create(path, branch, upstream) end Git.has_branch(branch, function(found_branch) - local config = require('git-worktree.config') + Config = require('git-worktree.config') local worktree_path if Path:new(path):is_absolute() then worktree_path = path @@ -120,7 +118,7 @@ function M.create(path, branch, upstream) create_wt_job:and_then_on_success(fetch) fetch:and_then_on_success(set_branch) - if config.autopush then + if Config.autopush then -- These are "optional" operations. -- We have to figure out how we want to handle these... set_branch:and_then(set_push) @@ -141,7 +139,6 @@ function M.create(path, branch, upstream) end vim.schedule(function() - local Hooks = require('git-worktree.hooks') Hooks.emit(Hooks.type.CREATE, path, branch, upstream) M.switch(path) end) @@ -149,7 +146,6 @@ function M.create(path, branch, upstream) else create_wt_job:after(function() vim.schedule(function() - local Hooks = require('git-worktree.hooks') Hooks.emit(Hooks.type.CREATE, path, branch, upstream) M.switch(path) end) @@ -182,7 +178,6 @@ function M.delete(path, force, opts) local delete = Git.delete_worktree_job(path, force) delete:after_success(vim.schedule_wrap(function() Log.info('delete after success') - local Hooks = require('git-worktree.hooks') Hooks.emit(Hooks.type.DELETE, path) if opts.on_success then opts.on_success() From 68630eac54f444bdf0f2328906522532d10a3d4f Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 11:21:31 -0400 Subject: [PATCH 28/33] ci: add bused tests --- .github/workflows/ci.yml | 58 ------------------------------- .github/workflows/commit_lint.yml | 13 ------- .github/workflows/release.yml | 18 ---------- .github/workflows/tests.yml | 22 ++++++++++++ 4 files changed, 22 insertions(+), 89 deletions(-) delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/commit_lint.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index b56f962..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: test - -on: - pull_request: - -jobs: - test: - name: Run Test - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - steps: - - uses: actions/checkout@v4 - - uses: rhysd/action-setup-vim@v1 - id: vim - with: - neovim: true - version: nightly - - - name: luajit - uses: leafo/gh-actions-lua@v10 - with: - luaVersion: "luajit-2.1.0-beta3" - - - uses: notomo/action-setup-nvim-lua@v1 - - run: luarocks install vusted - - run: luarocks install luacheck - - - name: install plenary.nvim - if: matrix.os != 'windows-latest' - run: | - git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary - - - name: install plenary.nvim on windows - if: matrix.os == 'windows-latest' - run: | - git clone --depth 1 https://github.com/nvim-lua/plenary.nvim .\plenary - ls .\plenary - ls .\plenary\lua - - - name: Run tests - if: matrix.os != 'windows-latest' - shell: bash - env: - VUSTED_NVIM: ${{ steps.vim.outputs.executable }} - VUSTED_ARGS: "--headless" - run: | - make test - - - name: Run tests - if: matrix.os == 'windows-latest' - shell: bash - env: - VUSTED_NVIM: ${{ steps.vim.outputs.executable }} - VUSTED_ARGS: "--headless" - run: | - make wintest diff --git a/.github/workflows/commit_lint.yml b/.github/workflows/commit_lint.yml deleted file mode 100644 index 1e5b5d8..0000000 --- a/.github/workflows/commit_lint.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: commit-lint -on: [pull_request] -jobs: - lint-commits: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - run: npm install --save-dev @commitlint/{cli,config-conventional} - - run: | - echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js - - run: npx commitlint --from HEAD~1 --to HEAD --verbose diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index a711b65..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: LuaRocks release -on: - push: - tags: # Will upload to luarocks.org when a tag is pushed - - "*" - pull_request: # Will test a local install without uploading to luarocks.org - -jobs: - luarocks-release: - runs-on: ubuntu-latest - name: LuaRocks upload - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: LuaRocks Upload - uses: nvim-neorocks/luarocks-tag-release@v5 - env: - LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..59d4fc3 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,22 @@ +--- +name: Run tests +on: + pull_request: ~ + push: + branches: + - main + +jobs: + build: + name: Run tests + runs-on: ubuntu-latest + strategy: + matrix: + neovim_version: ["nightly", "stable"] + + steps: + - uses: actions/checkout@v4 + - name: Run tests + uses: nvim-neorocks/nvim-busted-action@v1 + with: + nvim_version: ${{ matrix.neovim_version }} From 008d86258fec95607ec6ba74c6be0559b7f1ca5c Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 11:30:55 -0400 Subject: [PATCH 29/33] ci: add type-check --- .github/workflows/tests.yml | 2 +- .github/workflows/type-check.yml | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/type-check.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 59d4fc3..32fd026 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,5 +1,5 @@ --- -name: Run tests +name: tests on: pull_request: ~ push: diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml new file mode 100644 index 0000000..7834fdc --- /dev/null +++ b/.github/workflows/type-check.yml @@ -0,0 +1,19 @@ +--- +name: Type Check +on: + pull_request: ~ + push: + branches: + - main + +jobs: + build: + name: Type Check Code Base + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Type Check Code Base + uses: mrcjkb/lua-typecheck-action@v1 From 77f2355e4f022298386518f0e3f6510bceafd0c4 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 11:34:32 -0400 Subject: [PATCH 30/33] ci: add style check --- .github/workflows/style-check.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/style-check.yml diff --git a/.github/workflows/style-check.yml b/.github/workflows/style-check.yml new file mode 100644 index 0000000..8fe4541 --- /dev/null +++ b/.github/workflows/style-check.yml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json +--- +name: Style checking +on: + pull_request: ~ + push: + branches: + - main + +jobs: + stylua: + name: stylua + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4.1.6 + - uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: latest + args: --color always --check lua/ From 238d5d003dbcd185f5d1e9fceb311b4cfd64c3b1 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 11:37:29 -0400 Subject: [PATCH 31/33] ci: add dependabot.yml --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d202a33 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" From 253a445e6298303fd3f249d360e54d313f3b7aaf Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 12:28:17 -0400 Subject: [PATCH 32/33] ci: add convential commit checker --- .github/workflows/conventional-commits.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/workflows/conventional-commits.yml diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml new file mode 100644 index 0000000..aaf1b9b --- /dev/null +++ b/.github/workflows/conventional-commits.yml @@ -0,0 +1,14 @@ +name: Conventional Commits + +on: + pull_request: + branches: [ main ] + +jobs: + build: + name: Conventional Commits + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: webiny/action-conventional-commits@v1.3.0 + From 0ff9f71130aea660f0740e180ddd77e63b667992 Mon Sep 17 00:00:00 2001 From: Brian Ryall Date: Thu, 18 Jul 2024 12:39:29 -0400 Subject: [PATCH 33/33] ci: add luarocks release --- .github/workflows/release.yml | 30 ++++++++++++++++++++++++++++++ flake.nix | 1 + 2 files changed, 31 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2806b77 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,30 @@ +name: Release +on: + push: + tags: + - "*" + pull_request: + +jobs: + luarocks-release: + runs-on: ubuntu-latest + name: LuaRocks upload + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Fail if changelog entry does not exist + if: startsWith(github.ref, 'refs/tags/') + run: grep -q "${{ github.ref_name }}" CHANGELOG.md + - name: LuaRocks Upload + uses: nvim-neorocks/luarocks-tag-release@v7 + env: + LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} + with: + detailed_description: | + A plugin that helps to use git worktree operations, create, switch, and delete in neovim. + - name: GitHub Release + if: startsWith(github.ref, 'refs/tags/') + uses: ncipollo/release-action@v1 + with: + bodyFile: "CHANGELOG.md" + allowUpdates: true diff --git a/flake.nix b/flake.nix index 86c7a4d..9d6ca95 100644 --- a/flake.nix +++ b/flake.nix @@ -139,6 +139,7 @@ luarocks plenary-nvim ])) + git-cliff ]); }; };