This commit is contained in:
2026-03-12 19:21:42 +00:00
parent f2b2302f61
commit 6e1547ae48
11 changed files with 105 additions and 512 deletions

View File

@@ -29,6 +29,16 @@
pattern = "elixir,eelixir,heex";
command = "setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2";
}
{
event = "FileType";
group = "Christoph";
pattern = "opencode,opencode_output";
callback.__raw = ''
function()
vim.b.ministatusline_disable = true
end
'';
}
];
};
}

View File

@@ -1,21 +1,22 @@
{
{inputs', ...}: {
imports = [
./autocmd.nix
./mappings.nix
./options.nix
./plugins/blink-cmp.nix
./plugins/code-review.nix
./plugins/conform.nix
./plugins/diffview.nix
./plugins/grug-far.nix
./plugins/harpoon.nix
./plugins/hunk.nix
./plugins/jj-diffconflicts.nix
./plugins/jj-nvim.nix
./plugins/code-review.nix
./plugins/diffview.nix
./plugins/lsp.nix
./plugins/mini.nix
./plugins/oil.nix
./plugins/opencode.nix
./plugins/render-markdown.nix
./plugins/toggleterm.nix
./plugins/treesitter.nix
./plugins/zk.nix
@@ -24,6 +25,7 @@
programs.nixvim = {
enable = true;
defaultEditor = true;
package = inputs'.neovim-nightly-overlay.packages.default;
luaLoader.enable = true;
colorschemes.rose-pine = {
enable = true;
@@ -31,9 +33,6 @@
variant = "dawn";
};
};
extraConfigLua = ''
vim.ui.select = MiniPick.ui_select
'';
};
home.shellAliases = {

View File

@@ -5,9 +5,8 @@
format_on_save = {};
formatters_by_ft = {
nix = ["alejandra"];
javascript = ["prettier"];
typescript = ["prettier"];
vue = ["prettier"];
javascript = ["oxfmt"];
typescript = ["oxfmt"];
};
};
};

View File

@@ -30,7 +30,6 @@ in {
close_on_edit = false,
},
},
-- Disable default keymaps we set our own in mappings.nix
ui = {
log = {
keymaps = true,

View File

@@ -29,12 +29,12 @@
{ mode = 'n', keys = '<Leader>e', desc = '+Explore/+Edit' },
{ mode = 'n', keys = '<Leader>f', desc = '+Find' },
{ mode = 'n', keys = '<Leader>v', desc = '+VCS' },
{ mode = 'n', keys = '<Leader>l', desc = '+LSP' },
{ mode = 'x', keys = '<Leader>l', desc = '+LSP' },
{ mode = 'n', 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' },
{ mode = 'n', keys = '<Leader>l', desc = '+LSP' },
{ mode = 'x', keys = '<Leader>l', desc = '+LSP' },
{ mode = 'n', 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.g(),
require("mini.clue").gen_clues.marks(),
@@ -159,193 +159,17 @@
};
};
move = {};
notify = {
content.format.__raw = ''
function(notif)
local formatted = MiniNotify.default_format(notif)
return '\n ' .. formatted:gsub('\n', ' \n ') .. ' \n'
end
'';
window.config = {
border = "none";
title = "";
};
};
notify = {};
pairs = {};
pick = {};
splitjoin = {};
starter = {};
statusline = {
content.active.__raw = ''
function()
local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 })
local diff = MiniStatusline.section_diff({ trunc_width = 75 })
local diagnostics = MiniStatusline.section_diagnostics({ trunc_width = 75 })
local lsp = MiniStatusline.section_lsp({ trunc_width = 75 })
local filename = MiniStatusline.section_filename({ trunc_width = 140 })
local search = MiniStatusline.section_searchcount({ trunc_width = 75 })
return _G.CschStatusline.active({
mode = mode,
mode_hl = mode_hl,
diff = diff,
diagnostics = diagnostics,
lsp = lsp,
filename = filename,
search = search,
})
end
'';
};
statusline = {};
surround = {};
trailspace = {};
visits = {};
};
mockDevIcons = true;
};
extraConfigLua = ''
local mini_notify_group = vim.api.nvim_create_augroup('MiniNotifyDesign', { clear = true })
_G.CschStatusline = _G.CschStatusline or {}
local function to_hex(value)
return value and string.format('#%06x', value) or nil
end
local function get_hl(name)
return vim.api.nvim_get_hl(0, { name = name, link = false })
end
local function get_fg(name, fallback)
return to_hex(get_hl(name).fg) or fallback
end
local function get_bg(name, fallback)
return to_hex(get_hl(name).bg) or fallback
end
local function set_statusline_highlights()
local block_bg = get_bg('CursorLine', get_bg('Visual', '#373b41'))
local block_fg = get_fg('StatusLine', get_fg('Normal', '#c5c8c6'))
vim.api.nvim_set_hl(0, 'CschStatuslineBlock', { fg = block_fg, bg = block_bg })
end
local function statusline_group(hl, strings)
local parts = vim.tbl_filter(function(x)
return type(x) == 'string' and x ~= ""
end, strings or {})
if #parts == 0 then
return ""
end
return string.format('%%#%s# %s ', hl, table.concat(parts, ' '))
end
local function statusline_block(text, hl)
if text == nil or text == "" then
return ""
end
return string.format('%%#%s# %s ', hl, text)
end
local function statusline_filesize()
local size = math.max(vim.fn.line2byte(vim.fn.line('$') + 1) - 1, 0)
if size < 1024 then
return string.format('%dB', size)
elseif size < 1048576 then
return string.format('%.2fKiB', size / 1024)
end
return string.format('%.2fMiB', size / 1048576)
end
local function statusline_filetype()
local filetype = vim.bo.filetype
if filetype == "" then
return vim.bo.buftype ~= "" and vim.bo.buftype or 'text'
end
local icon = ""
if _G.MiniIcons ~= nil then
icon = _G.MiniIcons.get('filetype', filetype) or ""
end
return (icon ~= "" and (icon .. ' ') or "") .. filetype
end
local function statusline_fileinfo()
local label = statusline_filetype()
if MiniStatusline.is_truncated(120) or vim.bo.buftype ~= "" then
return label
end
return string.format('%s · %s', label, statusline_filesize())
end
local function statusline_location()
local line = vim.fn.line('.')
local total_lines = vim.fn.line('$')
local column = vim.fn.virtcol('.')
if MiniStatusline.is_truncated(90) then
return string.format('Ln %d Col %d', line, column)
end
return string.format('Ln %d/%d · Col %d', line, total_lines, column)
end
function _G.CschStatusline.active(parts)
local left = vim.tbl_filter(function(x)
return x ~= ""
end, {
statusline_block(parts.mode, parts.mode_hl),
statusline_group('MiniStatuslineDevinfo', { parts.diff, parts.diagnostics, parts.lsp }),
'%<',
statusline_group('MiniStatuslineFilename', { parts.filename }),
})
local right = vim.tbl_filter(function(x)
return x ~= ""
end, {
statusline_block(statusline_fileinfo(), 'CschStatuslineBlock'),
statusline_block(parts.search, 'CschStatuslineBlock'),
statusline_block(statusline_location(), parts.mode_hl),
})
return table.concat(left, "") .. '%=%#StatusLine#' .. table.concat(right, "")
end
local function set_mini_notify_highlights()
local border = vim.api.nvim_get_hl(0, { name = 'FloatBorder' })
local normal = vim.api.nvim_get_hl(0, { name = 'NormalFloat' })
local popup_bg = get_bg('Pmenu', get_bg('CursorLine', get_bg('NormalFloat', '#303446')))
local title = vim.api.nvim_get_hl(0, { name = 'FloatTitle' })
border.bg = 'NONE'
normal.bg = popup_bg
normal.bold = true
title.bg = 'NONE'
vim.api.nvim_set_hl(0, 'MiniNotifyBorder', border)
vim.api.nvim_set_hl(0, 'MiniNotifyNormal', normal)
vim.api.nvim_set_hl(0, 'MiniNotifyTitle', title)
end
vim.api.nvim_create_autocmd('ColorScheme', {
group = mini_notify_group,
callback = function()
set_mini_notify_highlights()
set_statusline_highlights()
end,
})
set_mini_notify_highlights()
set_statusline_highlights()
'';
};
}

View File

@@ -14,283 +14,15 @@
};
in {
programs.nixvim = {
extraPlugins = with pkgs.vimPlugins; [
extraPlugins = [
opencode-nvim
plenary-nvim
render-markdown-nvim
];
extraConfigLua = ''
local api = vim.api
local opencode_output_filetype = 'opencode_output'
local opencode_window_filetypes = {
opencode = true,
opencode_output = true,
}
local palette = {
base = '#faf4ed',
surface = '#fffaf3',
overlay = '#f2e9e1',
highlight_med = '#dfdad9',
text = '#575279',
subtle = '#797593',
muted = '#9893a5',
pine = '#286983',
iris = '#907aa9',
foam = '#56949f',
leaf = '#6d8f89',
gold = '#ea9d34',
rose = '#d7827e',
love = '#b4637a',
}
local function set_highlights(highlights)
for group, spec in pairs(highlights) do
api.nvim_set_hl(0, group, spec)
end
end
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 collect_conceal_marks(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
local function set_opencode_output_conceal()
if vim.bo.filetype ~= opencode_output_filetype then
return
end
vim.wo.conceallevel = 3
vim.wo.concealcursor = 'nvic'
end
local function hide_opencode_statusline()
if not opencode_window_filetypes[vim.bo.filetype] then
return
end
vim.wo.statusline = ' '
end
vim.treesitter.language.register('markdown', opencode_output_filetype)
vim.treesitter.language.register('markdown_inline', opencode_output_filetype)
api.nvim_create_autocmd({ 'FileType', 'BufWinEnter', 'WinEnter' }, {
callback = set_opencode_output_conceal,
})
api.nvim_create_autocmd({ 'FileType', 'BufWinEnter', 'WinEnter', 'BufEnter' }, {
pattern = '*',
callback = hide_opencode_statusline,
})
set_highlights({
RenderMarkdownCode = { bg = palette.surface },
RenderMarkdownCodeBorder = { fg = palette.highlight_med, bg = palette.surface },
RenderMarkdownCodeInline = { bg = palette.surface },
RenderMarkdownH1 = { fg = palette.pine, bold = true },
RenderMarkdownH2 = { fg = palette.iris, bold = true },
RenderMarkdownH3 = { fg = palette.foam, bold = true },
RenderMarkdownH4 = { fg = palette.gold, bold = true },
OpencodeInputLegend = { fg = palette.subtle, bold = true },
OpencodeAgentBuild = { bg = palette.muted, fg = palette.base, bold = true },
})
local render_markdown_config = {
anti_conceal = { enabled = false },
heading = {
icons = { ' ', ' ', ' ', '· ', '· ', '· ' },
backgrounds = {},
position = 'inline',
width = 'block',
left_pad = 0,
right_pad = 2,
border = false,
sign = false,
},
code = {
sign = false,
width = 'full',
left_pad = 2,
right_pad = 0,
border = 'thin',
language_icon = false,
language_name = true,
},
bullet = {
icons = { '·', '', '·', '' },
},
custom_handlers = {
markdown_inline = {
extends = true,
parse = collect_conceal_marks,
},
},
file_types = { opencode_output_filetype },
win_options = {
conceallevel = { rendered = 3 },
concealcursor = { rendered = 'nvic' },
},
}
require('render-markdown').setup(render_markdown_config)
local opencode_icon_overrides = {
header_user = '',
header_assistant = '',
run = '',
task = '',
read = '',
edit = '',
write = '',
plan = '',
search = '',
web = '',
list = '',
tool = '',
snapshot = '',
restore_point = '',
file = '·',
folder = '·',
attached_file = '·',
agent = '·',
reference = '·',
reasoning = '',
question = '?',
border = '',
}
require('opencode').setup({
server = {
url = 'http://127.0.0.1',
port = 18822,
auto_kill = false,
},
input = {
text = {
wrap = true,
},
},
require("opencode").setup({
debug = {
show_ids = false,
},
ui = {
icons = {
preset = 'nerdfonts',
overrides = opencode_icon_overrides,
},
},
})
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')
local function format_reasoning_title(part)
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
return title
end
local function highlight_reasoning_block(output, start_line)
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')
return
end
output:add_extmark(start_line - 1, {
line_hl_group = 'OpencodeReasoningText',
})
end
formatter._format_reasoning = function(output, part)
local text = vim.trim(part.text or "")
local start_line = output:get_line_count() + 1
format_utils.format_action(output, icons.get('reasoning'), format_reasoning_title(part), "")
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
highlight_reasoning_block(output, start_line)
end
end
'';
};
}

View File

@@ -0,0 +1,9 @@
{
programs.nixvim.plugins.render-markdown = {
enable = true;
settings = {
anti_conceal = {enabled = false;};
file_types = ["markdown" "opencode_output"];
};
};
}

View File

@@ -9,52 +9,5 @@
indent.enable = true;
};
};
# Register missing treesitter predicates for compatibility with newer grammars
extraConfigLuaPre = ''
do
local query = require("vim.treesitter.query")
local predicates = query.list_predicates()
if not vim.tbl_contains(predicates, "is-not?") then
query.add_predicate("is-not?", function(match, pattern, source, predicate)
local dominated_by = predicate[2]
local dominated = false
for _, node in pairs(match) do
if type(node) == "userdata" then
local current = node:parent()
while current do
if current:type() == dominated_by then
dominated = true
break
end
current = current:parent()
end
end
end
return not dominated
end, { force = true, all = true })
end
end
-- Fix grammar-bundled treesitter queries that use #match? with Lua pattern
-- syntax (e.g. %d) instead of Vim regex. Neovim 0.11 picks the first
-- non-extending query file in the rtp as the base, so the grammar-bundled
-- (buggy) queries take precedence over the corrected site-level queries.
-- Override affected languages with the site-level version.
do
local langs = { "sql" }
for _, lang in ipairs(langs) do
local files = vim.api.nvim_get_runtime_file(
"queries/" .. lang .. "/highlights.scm", true)
if #files > 1 then
local f = io.open(files[#files])
if f then
vim.treesitter.query.set(lang, "highlights", f:read("*all"))
f:close()
end
end
end
end
'';
};
}