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)