Compare commits

...

3 Commits

8 changed files with 428 additions and 18 deletions

View File

@@ -9,6 +9,9 @@
./plugins/harpoon.nix ./plugins/harpoon.nix
./plugins/hunk.nix ./plugins/hunk.nix
./plugins/jj-diffconflicts.nix ./plugins/jj-diffconflicts.nix
./plugins/jj-nvim.nix
./plugins/code-review.nix
./plugins/diffview.nix
./plugins/lsp.nix ./plugins/lsp.nix
./plugins/mini.nix ./plugins/mini.nix
./plugins/oil.nix ./plugins/oil.nix

View File

@@ -117,16 +117,54 @@
action = ":Pick visit_paths<CR>"; action = ":Pick visit_paths<CR>";
options.desc = "Visit paths (cwd)"; options.desc = "Visit paths (cwd)";
} }
# g - git # v - vcs
{ {
mode = "n"; mode = "n";
key = "<leader>gc"; key = "<leader>va";
action = ":J annotate<CR>";
options.desc = "Annotate (blame)";
}
{
mode = "n";
key = "<leader>vc";
action = ":JJDiffConflicts<CR>"; action = ":JJDiffConflicts<CR>";
options.desc = "Resolve conflicts"; options.desc = "Resolve conflicts";
} }
{ {
mode = "n"; mode = "n";
key = "<leader>gg"; key = "<leader>vd";
action.__raw = ''
function()
require('jj.cmd').diff()
end
'';
options.desc = "Diff (current file)";
}
{
mode = "n";
key = "<leader>vD";
action = ":DiffviewOpen<CR>";
options.desc = "Diffview (all changes)";
}
{
mode = "n";
key = "<leader>ve";
action.__raw = ''
function()
require('jj.cmd').describe()
end
'';
options.desc = "Describe (edit message)";
}
{
mode = "n";
key = "<leader>vf";
action = ":J fetch<CR>";
options.desc = "Fetch";
}
{
mode = "n";
key = "<leader>vv";
action.__raw = '' action.__raw = ''
function() function()
require('toggleterm.terminal').Terminal:new({ cmd = 'jjui', direction = 'float' }):toggle() require('toggleterm.terminal').Terminal:new({ cmd = 'jjui', direction = 'float' }):toggle()
@@ -134,6 +172,115 @@
''; '';
options.desc = "jjui"; options.desc = "jjui";
} }
{
mode = "n";
key = "<leader>vh";
action = ":DiffviewFileHistory %<CR>";
options.desc = "File history";
}
{
mode = "n";
key = "<leader>vH";
action = ":DiffviewFileHistory<CR>";
options.desc = "Branch history";
}
{
mode = "n";
key = "<leader>vl";
action.__raw = ''
function()
require('jj.cmd').log()
end
'';
options.desc = "Log";
}
{
mode = "n";
key = "<leader>vn";
action.__raw = ''
function()
require('jj.cmd').new()
end
'';
options.desc = "New change";
}
{
mode = "n";
key = "<leader>vp";
action = ":J git push<CR>";
options.desc = "Push";
}
{
mode = "n";
key = "<leader>vq";
action = ":DiffviewClose<CR>";
options.desc = "Close diffview";
}
{
mode = "n";
key = "<leader>vs";
action.__raw = ''
function()
require('jj.cmd').status()
end
'';
options.desc = "Status";
}
# r - review
{
mode = ["n" "v"];
key = "<leader>rc";
action = ":CodeReviewComment<CR>";
options.desc = "Add comment";
}
{
mode = "n";
key = "<leader>rd";
action = ":CodeReviewDeleteComment<CR>";
options.desc = "Delete comment";
}
{
mode = "n";
key = "<leader>rl";
action = ":CodeReviewList<CR>";
options.desc = "List comments";
}
{
mode = "n";
key = "<leader>ro";
action = ":CodeReviewResolve<CR>";
options.desc = "Resolve thread";
}
{
mode = "n";
key = "<leader>rp";
action = ":CodeReviewPreview<CR>";
options.desc = "Preview review";
}
{
mode = "n";
key = "<leader>rr";
action = ":CodeReviewReply<CR>";
options.desc = "Reply to comment";
}
{
mode = "n";
key = "<leader>rs";
action = ":CodeReviewShowComment<CR>";
options.desc = "Show comment";
}
{
mode = "n";
key = "<leader>rx";
action = ":CodeReviewClear<CR>";
options.desc = "Clear all comments";
}
{
mode = "n";
key = "<leader>ry";
action = ":CodeReviewCopy<CR>";
options.desc = "Copy review to clipboard";
}
# l - lsp/formatter # l - lsp/formatter
{ {
mode = "n"; mode = "n";

View File

@@ -0,0 +1,37 @@
{pkgs, ...}: let
code-review-nvim =
pkgs.vimUtils.buildVimPlugin {
pname = "code-review-nvim";
version = "unstable-2026-03-10";
src =
pkgs.fetchFromGitHub {
owner = "choplin";
repo = "code-review.nvim";
rev = "ed91462e20bd08c3be71efb11a4a7d00459f0b47";
hash = "sha256-WpbQswkUpB4Nblos8+5UE5I/PHUQOi+RQ+hj4CCdL4o=";
};
doCheck = false;
};
in {
programs.nixvim = {
extraPlugins = [
code-review-nvim
];
extraConfigLua = ''
require('code-review').setup({
comment = {
storage = {
backend = "file",
file = {
dir = ".code-review",
},
},
},
output = {
format = "minimal",
},
keymaps = false,
})
'';
};
}

View File

@@ -0,0 +1,26 @@
{pkgs, ...}: {
programs.nixvim = {
extraPlugins = with pkgs.vimPlugins; [
diffview-nvim
];
extraConfigLua = ''
require('diffview').setup({
enhanced_diff_hl = true,
view = {
default = { layout = "diff2_horizontal" },
merge_tool = { layout = "diff3_mixed", disable_diagnostics = true },
file_history = { layout = "diff2_horizontal" },
},
default_args = {
DiffviewOpen = { "--imply-local" },
},
hooks = {
diff_buf_read = function(bufnr)
vim.opt_local.wrap = false
vim.opt_local.list = false
end,
},
})
'';
};
}

View File

@@ -0,0 +1,42 @@
{pkgs, ...}: let
jj-nvim =
pkgs.vimUtils.buildVimPlugin {
pname = "jj-nvim";
version = "unstable-2026-03-10";
src =
pkgs.fetchFromGitHub {
owner = "NicolasGB";
repo = "jj.nvim";
rev = "bbba4051c862473637e98277f284d12b050588ca";
hash = "sha256-nokftWcAmmHX6UcH6O79xkLwbUpq1W8N9lf1e+NyGqE=";
};
doCheck = false;
};
in {
programs.nixvim = {
extraPlugins = [
jj-nvim
];
extraConfigLua = ''
require('jj').setup({
diff = {
backend = "diffview",
},
cmd = {
describe = {
editor = { type = "buffer" },
},
log = {
close_on_edit = false,
},
},
-- Disable default keymaps we set our own in mappings.nix
ui = {
log = {
keymaps = true,
},
},
})
'';
};
}

View File

@@ -27,11 +27,13 @@
{ {
{ mode = 'n', keys = '<Leader>e', desc = '+Explore/+Edit' }, { mode = 'n', keys = '<Leader>e', desc = '+Explore/+Edit' },
{ mode = 'n', keys = '<Leader>f', desc = '+Find' }, { mode = 'n', keys = '<Leader>f', desc = '+Find' },
{ mode = 'n', keys = '<Leader>g', desc = '+Git' }, { mode = 'n', keys = '<Leader>v', desc = '+VCS' },
{ mode = 'n', keys = '<Leader>l', desc = '+LSP' }, { mode = 'n', keys = '<Leader>l', desc = '+LSP' },
{ mode = 'x', keys = '<Leader>l', desc = '+LSP' }, { mode = 'x', keys = '<Leader>l', desc = '+LSP' },
{ mode = 'n', keys = '<Leader>o', desc = '+OpenCode' }, { mode = 'n', keys = '<Leader>o', desc = '+OpenCode' },
{ mode = 'x', keys = '<Leader>o', desc = '+OpenCode' }, { mode = 'x', keys = '<Leader>o', desc = '+OpenCode' },
{ mode = 'n', keys = '<Leader>r', desc = '+Review' },
{ mode = 'v', keys = '<Leader>r', desc = '+Review' },
require("mini.clue").gen_clues.builtin_completion(), require("mini.clue").gen_clues.builtin_completion(),
require("mini.clue").gen_clues.g(), require("mini.clue").gen_clues.g(),
require("mini.clue").gen_clues.marks(), require("mini.clue").gen_clues.marks(),

View File

@@ -20,9 +20,99 @@ in {
render-markdown-nvim render-markdown-nvim
]; ];
extraConfigLua = '' extraConfigLua = ''
local opencode_markdown_conceal_query = vim.treesitter.query.parse('markdown_inline', [[
[
(emphasis_delimiter)
(code_span_delimiter)
(latex_span_delimiter)
] @conceal
(inline_link
[
"["
"]"
"("
(link_destination)
")"
] @conceal)
(full_reference_link
[
"["
"]"
(link_label)
] @conceal)
(collapsed_reference_link
[
"["
"]"
] @conceal)
(shortcut_link
[
"["
"]"
] @conceal)
(image
[
"!"
"["
"]"
"("
(link_destination)
")"
] @conceal)
]])
local function set_opencode_output_conceal()
if vim.bo.filetype ~= 'opencode_output' then
return
end
vim.wo.conceallevel = 3
vim.wo.concealcursor = 'nvic'
end
vim.treesitter.language.register('markdown', 'opencode_output')
vim.treesitter.language.register('markdown_inline', 'opencode_output')
vim.api.nvim_create_autocmd({ 'FileType', 'BufWinEnter', 'WinEnter' }, {
callback = set_opencode_output_conceal,
})
require('render-markdown').setup({ require('render-markdown').setup({
anti_conceal = { enabled = false }, anti_conceal = { enabled = false },
file_types = { 'markdown', 'opencode_output' }, custom_handlers = {
markdown_inline = {
extends = true,
parse = function(ctx)
local marks = {}
for _, node in opencode_markdown_conceal_query:iter_captures(ctx.root, ctx.buf) do
local start_row, start_col, end_row, end_col = node:range()
marks[#marks + 1] = {
conceal = true,
start_row = start_row,
start_col = start_col,
opts = {
end_row = end_row,
end_col = end_col,
conceal = "",
},
}
end
return marks
end,
},
},
file_types = { 'opencode_output' },
win_options = {
conceallevel = { rendered = 3 },
concealcursor = { rendered = "nvic" },
},
}) })
require('opencode').setup({ require('opencode').setup({
server = { server = {
@@ -30,7 +120,54 @@ in {
port = 18822, port = 18822,
auto_kill = false, auto_kill = false,
}, },
ui = {
icons = {
preset = 'nerdfonts',
},
questions = {
use_vim_ui_select = true,
},
},
}) })
do
local config = require('opencode.config')
local formatter = require('opencode.ui.formatter')
local format_utils = require('opencode.ui.formatter.utils')
local icons = require('opencode.ui.icons')
local util = require('opencode.util')
formatter._format_reasoning = function(output, part)
local text = vim.trim(part.text or "")
local start_line = output:get_line_count() + 1
local title = 'Reasoning'
local time = part.time
if time and type(time) == 'table' and time.start then
local duration_text = util.format_duration_seconds(time.start, time['end'])
if duration_text then
title = string.format('%s %s', title, duration_text)
end
end
format_utils.format_action(output, icons.get('reasoning'), title, "")
if config.ui.output.tools.show_reasoning_output and text ~= "" then
output:add_empty_line()
output:add_lines(vim.split(text, '\n'), ' ')
output:add_empty_line()
end
local end_line = output:get_line_count()
if end_line - start_line > 1 then
formatter.add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')
else
output:add_extmark(start_line - 1, {
line_hl_group = 'OpencodeReasoningText',
})
end
end
end
''; '';
}; };
} }

View File

@@ -0,0 +1,16 @@
import type { Plugin } from "@opencode-ai/plugin";
export const DirenvPlugin: Plugin = async ({ $ }) => {
return {
"shell.env": async (input, output) => {
try {
const exported = await $`direnv export json`
.cwd(input.cwd)
.quiet()
.json();
Object.assign(output.env, exported);
} catch {}
},
};
};