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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ home-manager.users.<user>.home.packages = [

- `codediff.nix`: Configures a read-only review workflow for working-tree, branch, and commit-history diffs.
- `jj.nix`: Configures Jujutsu commands and key mappings.
- `lazygit.nix`: Configures the LazyGit plugin for Git integration.
- `lazygit.nix`: Configures LazyGit and opens selected worktrees in new, rooted editor tabs.
- `gitsigns.nix`: Configures GitSigns diff markers, hunk navigation, inline previews, blame, and word diffs.

### Utils
Expand Down
106 changes: 97 additions & 9 deletions config/plugins/git/lazygit.nix
Original file line number Diff line number Diff line change
@@ -1,20 +1,108 @@
{ pkgs, ... }:
{
extraPlugins = with pkgs.vimPlugins; [
lazygit-nvim
];
_: {
plugins.lazygit.enable = true;

extraConfigLua = # lua
''
require("telescope").load_extension("lazygit")

local function normalize(path)
if not path or path == "" then
return nil
end

return vim.uv.fs_realpath(path) or vim.fs.normalize(path)
end

local function git_root(path)
local result = vim.system(
{ "git", "-C", path, "rev-parse", "--show-toplevel" },
{ text = true }
):wait()

if result.code ~= 0 then
return nil
end

return normalize(vim.trim(result.stdout or ""))
end

local function read_handoff(path)
local ok, lines = pcall(vim.fn.readfile, path)
vim.fn.delete(path)

if not ok or not lines[1] then
return nil
end

return git_root(vim.trim(lines[1]))
end

local function open_worktree(path)
vim.cmd.tabnew()
vim.cmd.tcd(vim.fn.fnameescape(path))

local snacks_ok, snacks = pcall(require, "snacks")
if snacks_ok then
snacks.dashboard()
end

vim.notify(
("Opened worktree %s"):format(vim.fs.basename(path)),
vim.log.levels.INFO,
{ title = "LazyGit" }
)
end

local handoff = vim.fn.tempname()
local previous_handoff = vim.env.LAZYGIT_NEW_DIR_FILE
local previous_callback = vim.g.lazygit_on_exit_callback

vim.env.LAZYGIT_NEW_DIR_FILE = handoff
vim.g.lazygit_on_exit_callback = function()
local source_root = git_root(vim.uv.cwd())
local target_root = read_handoff(handoff)

if type(previous_callback) == "function" then
local ok, err = pcall(previous_callback)
if not ok then
vim.notify(err, vim.log.levels.ERROR, { title = "LazyGit callback" })
end
end

if target_root and target_root ~= source_root then
open_worktree(target_root)
end
end

local lazygit_worktree_group = vim.api.nvim_create_augroup("lazygit_worktree", { clear = true })

vim.api.nvim_create_autocmd("TermClose", {
group = lazygit_worktree_group,
callback = function(args)
if vim.bo[args.buf].filetype == "lazygit" and vim.v.event.status ~= 0 then
vim.fn.delete(handoff)
end
end,
})

extraConfigLua = ''
require("telescope").load_extension("lazygit")
'';
vim.api.nvim_create_autocmd("VimLeavePre", {
group = lazygit_worktree_group,
once = true,
callback = function()
vim.fn.delete(handoff)
vim.env.LAZYGIT_NEW_DIR_FILE = previous_handoff
vim.g.lazygit_on_exit_callback = previous_callback
end,
})
'';

keymaps = [
{
mode = "n";
key = "<leader>gg";
action = "<cmd>LazyGit<CR>";
options = {
desc = "LazyGit (root dir)";
desc = "LazyGit (worktree aware)";
};
}
];
Expand Down