Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions lua/tabi/storage/local.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ local M = {}
local utils = require("tabi.utils")

--- Get storage directory path
--- Uses git common directory to support git worktrees, where .git is a file rather than a directory.
---@return string|nil
function M.get_storage_dir()
local git_root = utils.get_git_root()
if not git_root then
local git_common_dir = utils.get_git_common_dir()
if not git_common_dir then
return nil
end
return git_root .. "/.git/tabi"
return git_common_dir .. "/tabi"
end

--- Get sessions directory path
Expand Down
23 changes: 23 additions & 0 deletions lua/tabi/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,29 @@ function M.get_git_root()
return root and vim.trim(root) or nil
end

--- Get git common directory (resolves git worktree gitfiles to the actual .git directory)
--- In a normal repo, returns the same as .git directory.
--- In a worktree, returns the main repository's .git directory instead of the worktree-specific one.
---@return string|nil
function M.get_git_common_dir()
local handle = io.popen("git rev-parse --git-common-dir 2>/dev/null")
if not handle then
return nil
end
local dir = handle:read("*a")
handle:close()
if not dir or vim.trim(dir) == "" then
return nil
end
dir = vim.trim(dir)
-- --git-common-dir may return a relative path; convert to absolute
if not vim.startswith(dir, "/") then
local cwd = vim.fn.getcwd()
dir = cwd .. "/" .. dir
end
return dir
end

--- Ensure directory exists
---@param path string
function M.ensure_dir(path)
Expand Down
30 changes: 22 additions & 8 deletions test/tabi/storage/local_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ local utils = require("tabi.utils")

describe("tabi.storage.local", function()
local temp_dir
local original_get_git_root
local original_get_git_common_dir
local original_is_git_repo

before_each(function()
-- Create temporary directory to simulate git repo
-- Create temporary directory to simulate git repo's .git directory
temp_dir = vim.fn.tempname() .. "_tabi_local_test"
vim.fn.mkdir(temp_dir .. "/.git", "p")

-- Mock git functions
original_get_git_root = utils.get_git_root
original_get_git_common_dir = utils.get_git_common_dir
original_is_git_repo = utils.is_git_repo

utils.get_git_root = function()
return temp_dir
utils.get_git_common_dir = function()
return temp_dir .. "/.git"
end

utils.is_git_repo = function()
Expand All @@ -26,7 +26,7 @@ describe("tabi.storage.local", function()

after_each(function()
-- Restore original functions
utils.get_git_root = original_get_git_root
utils.get_git_common_dir = original_get_git_common_dir
utils.is_git_repo = original_is_git_repo

-- Clean up temporary directory
Expand All @@ -42,12 +42,26 @@ describe("tabi.storage.local", function()
end)

it("should return nil when not in git repo", function()
utils.get_git_root = function()
utils.get_git_common_dir = function()
return nil
end
local dir = local_storage.get_storage_dir()
assert.is_nil(dir)
end)

it("should use the common git dir so worktrees share storage", function()
-- Simulate a worktree: git_common_dir points to the main repo's .git
local main_git_dir = vim.fn.tempname() .. "_main_git"
vim.fn.mkdir(main_git_dir, "p")
utils.get_git_common_dir = function()
return main_git_dir
end

local dir = local_storage.get_storage_dir()
assert.are.equal(main_git_dir .. "/tabi", dir)

vim.fn.delete(main_git_dir, "rf")
end)
end)

describe("get_sessions_dir", function()
Expand All @@ -57,7 +71,7 @@ describe("tabi.storage.local", function()
end)

it("should return nil when not in git repo", function()
utils.get_git_root = function()
utils.get_git_common_dir = function()
return nil
end
local dir = local_storage.get_sessions_dir()
Expand Down
14 changes: 14 additions & 0 deletions test/tabi/utils_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ describe("tabi.utils", function()
end)
end)

describe("get_git_common_dir", function()
it("should return a non-empty string when in a git repo", function()
-- This test runs inside the tabi.nvim git repo
local dir = utils.get_git_common_dir()
-- May be nil in environments without git, so only assert format when non-nil
if dir ~= nil then
assert.is_string(dir)
assert.is_true(#dir > 0)
-- Must be an absolute path
assert.is_true(vim.startswith(dir, "/"), "get_git_common_dir should return an absolute path, got: " .. dir)
end
end)
end)

describe("ensure_dir", function()
local temp_dir

Expand Down