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
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,15 @@ home-manager.users.<user>.home.packages = [

### Git

- `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.
- `gitsigns.nix`: Configures the GitSigns plugin for displaying Git diff information.
- `gitsigns.nix`: Configures GitSigns diff markers, hunk navigation, inline previews, blame, and word diffs.

### Utils

- `trouble.nix`: Provides persistent diagnostics, quickfix, location-list, and TODO triage views.
- `overseer.nix`: Runs bounded, repo-aware validation tasks while keeping persistent sessions in cmux.
- `telescope.nix`: Configures the Telescope plugin for fuzzy finding and picking.
- `whichkey.nix`: Configures the WhichKey plugin for displaying key mappings.
- `extra_plugins.nix`: Configures additional plugins.
Expand Down
3 changes: 3 additions & 0 deletions config/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,14 @@ _: {
./plugins/lsp/fidget.nix

# Git
./plugins/git/codediff.nix
./plugins/git/jj.nix
./plugins/git/lazygit.nix
./plugins/git/gitsigns.nix

# Utils
./plugins/utils/trouble.nix
./plugins/utils/overseer.nix
./plugins/utils/telescope.nix
./plugins/utils/whichkey.nix
./plugins/utils/extra_plugins.nix
Expand Down
143 changes: 143 additions & 0 deletions config/plugins/git/codediff.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
{ lib, ... }:
let
reviewLua = # lua
''
local function git_root()
local name = vim.api.nvim_buf_get_name(0)
local start = name ~= "" and vim.fs.dirname(name) or vim.uv.cwd()
return (start and vim.fs.root(start, ".git")) or vim.uv.cwd()
end

local function git_ref_exists(root, ref)
local result = vim.system(
{ "git", "rev-parse", "--verify", "--quiet", ref },
{ cwd = root, text = true }
):wait()
return result.code == 0
end

local function review_base()
local root = git_root()
local result = vim.system(
{ "git", "symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD" },
{ cwd = root, text = true }
):wait()

if result.code == 0 then
local ref = vim.trim(result.stdout or "")
if ref ~= "" then
return ref
end
end

for _, ref in ipairs({ "origin/main", "origin/master", "main", "master" }) do
if git_ref_exists(root, ref) then
return ref
end
end

return nil
end

local function with_review_base(callback)
local base = review_base()
if not base then
vim.notify("Could not determine the default review branch", vim.log.levels.ERROR)
return
end
callback(base)
end

vim.api.nvim_create_user_command("CodeReviewBranch", function()
with_review_base(function(base)
vim.cmd("CodeDiff " .. vim.fn.fnameescape(base .. "...HEAD"))
end)
end, { desc = "Review branch changes against its merge base" })

vim.api.nvim_create_user_command("CodeReviewHistory", function()
with_review_base(function(base)
vim.cmd("CodeDiff history " .. vim.fn.fnameescape(base .. "..HEAD") .. " --reverse")
end)
end, { desc = "Review branch commits in chronological order" })
'';
in
{
plugins.codediff = {
enable = true;
settings = {
diff = {
layout = "side-by-side";
compact = true;
compact_context_lines = 4;
compute_moves = true;
cycle_hunks_across_files = true;
disable_inlay_hints = true;
jump_to_first_change = true;
};
explorer = {
initial_focus = "explorer";
view_mode = "tree";
};
history = {
initial_focus = "history";
view_mode = "tree";
};
keymaps = {
conflict = {
accept_all_both = false;
accept_all_current = false;
accept_all_incoming = false;
accept_both = false;
accept_current = false;
accept_incoming = false;
diffget_current = false;
diffget_incoming = false;
discard = false;
discard_all = false;
};
view = {
diff_get = false;
diff_put = false;
discard_hunk = false;
stage_hunk = false;
toggle_stage = false;
unstage_hunk = false;
};
explorer = {
restore = false;
stage_all = false;
unstage_all = false;
};
};
};
};

extraConfigLua = lib.mkAfter reviewLua;

keymaps = [
{
mode = "n";
key = "<leader>gd";
action = "<cmd>CodeDiff<cr>";
options = {
desc = "Review working tree";
};
}
{
mode = "n";
key = "<leader>gD";
action = "<cmd>CodeReviewBranch<cr>";
options = {
desc = "Review branch changes";
};
}
{
mode = "n";
key = "<leader>gH";
action = "<cmd>CodeReviewHistory<cr>";
options = {
desc = "Review branch history";
};
}
];
}
49 changes: 48 additions & 1 deletion config/plugins/git/gitsigns.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
_: {
{
plugins.gitsigns = {
enable = true;
settings = {
preview_config = {
border = "rounded";
};
signs = {
add = {
text = " ";
Expand All @@ -22,6 +25,50 @@ _: {
text = "󱂧 ";
};
};
word_diff = false;
};
};

keymaps = [
{
mode = "n";
key = "]h";
action = "<cmd>Gitsigns nav_hunk next<cr>";
options = {
desc = "Next Git hunk";
};
}
{
mode = "n";
key = "[h";
action = "<cmd>Gitsigns nav_hunk prev<cr>";
options = {
desc = "Previous Git hunk";
};
}
{
mode = "n";
key = "<leader>ghp";
action = "<cmd>Gitsigns preview_hunk_inline<cr>";
options = {
desc = "Preview Git hunk inline";
};
}
{
mode = "n";
key = "<leader>ghb";
action = "<cmd>Gitsigns blame_line<cr>";
options = {
desc = "Blame Git line";
};
}
{
mode = "n";
key = "<leader>gW";
action = "<cmd>Gitsigns toggle_word_diff<cr>";
options = {
desc = "Toggle Git word diff";
};
}
];
}
1 change: 1 addition & 0 deletions config/plugins/git/jj.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
cmd.describe.editor = {
type = "buffer";
};
diff.backend = "codediff";
};
};

Expand Down
147 changes: 147 additions & 0 deletions config/plugins/utils/overseer.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
{ lib, ... }:
let
projectTasksLua = # lua
''
local overseer = require("overseer")

local function find_root(marker, start, kind)
local opts = {
upward = true,
path = start,
}
if kind then
opts.type = kind
end

local match = vim.fs.find(marker, opts)[1]
return match and vim.fs.dirname(match) or nil
end

local function validation_task(name, description, command, cwd)
return {
name = name,
desc = description,
tags = { overseer.TAG.TEST },
builder = function()
return {
cmd = command,
cwd = cwd,
components = {
{
"on_output_quickfix",
items_only = true,
open = false,
set_diagnostics = true,
},
"default",
},
}
end,
}
end

overseer.register_template({
name = "project checks",
generator = function(search)
local tasks = {}

local flake_root = find_root("flake.nix", search.dir, "file")
if flake_root and vim.fn.executable("nix") == 1 then
table.insert(tasks, validation_task(
"project: nix flake check",
"Run flake checks, including untracked files, without changing flake.lock",
{ "nix", "flake", "check", "path:.", "--no-write-lock-file" },
flake_root
))
end

local go_root = find_root("go.mod", search.dir, "file")
if go_root and vim.fn.executable("go") == 1 then
table.insert(tasks, validation_task(
"project: go test ./...",
"Run all Go tests in the nearest module",
{ "go", "test", "./..." },
go_root
))
end

local git_root = find_root(".git", search.dir)
if git_root and vim.fn.executable("git") == 1 then
table.insert(tasks, validation_task(
"project: git diff --check",
"Check the working tree for whitespace errors",
{ "git", "diff", "--check" },
git_root
))
end

if vim.tbl_isempty(tasks) then
return "No supported project checks found"
end
return tasks
end,
})

vim.api.nvim_create_user_command("OverseerRestartLast", function()
local task_list = require("overseer.task_list")
local tasks = overseer.list_tasks({
status = {
overseer.STATUS.SUCCESS,
overseer.STATUS.FAILURE,
overseer.STATUS.CANCELED,
},
sort = task_list.sort_finished_recently,
})

if vim.tbl_isempty(tasks) then
vim.notify("No completed tasks found", vim.log.levels.WARN)
return
end
overseer.run_action(tasks[1], "restart")
end, { desc = "Restart the most recently completed task" })
'';
in
{
plugins.overseer = {
enable = true;
settings = {
dap = false;
templates = [ "builtin" ];
task_list = {
default_detail = 1;
direction = "bottom";
min_height = 10;
max_height = 20;
};
};
};

extraConfigLua = lib.mkAfter projectTasksLua;

keymaps = [
{
mode = "n";
key = "<leader>or";
action = "<cmd>OverseerRun<cr>";
options.desc = "Run project task";
}
{
mode = "n";
key = "<leader>ot";
action = "<cmd>OverseerToggle<cr>";
options.desc = "Toggle task list";
}
{
mode = "n";
key = "<leader>oa";
action = "<cmd>OverseerTaskAction<cr>";
options.desc = "Task action";
}
{
mode = "n";
key = "<leader>ol";
action = "<cmd>OverseerRestartLast<cr>";
options.desc = "Restart last task";
}
];
}
Loading