more
This commit is contained in:
@@ -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
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
format_on_save = {};
|
||||
formatters_by_ft = {
|
||||
nix = ["alejandra"];
|
||||
javascript = ["prettier"];
|
||||
typescript = ["prettier"];
|
||||
vue = ["prettier"];
|
||||
javascript = ["oxfmt"];
|
||||
typescript = ["oxfmt"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@ in {
|
||||
close_on_edit = false,
|
||||
},
|
||||
},
|
||||
-- Disable default keymaps — we set our own in mappings.nix
|
||||
ui = {
|
||||
log = {
|
||||
keymaps = true,
|
||||
|
||||
@@ -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()
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
9
modules/_neovim/plugins/render-markdown.nix
Normal file
9
modules/_neovim/plugins/render-markdown.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
programs.nixvim.plugins.render-markdown = {
|
||||
enable = true;
|
||||
settings = {
|
||||
anti_conceal = {enabled = false;};
|
||||
file_types = ["markdown" "opencode_output"];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user