cmp is back baby

This commit is contained in:
Zacharias-Brohn
2026-02-25 11:30:39 +01:00
parent 00c2714194
commit db2b2d364f
18 changed files with 760 additions and 200 deletions
+13
View File
@@ -0,0 +1,13 @@
function! neoformat#formatters#qml#enabled() abort
return ['qmlformat']
endfunction
function! neoformat#formatters#qml#qmlformat() abort
return {
\ 'exe': '/usr/lib/qt6/bin/qmlformat',
\ 'args': ['-t', '-n', '--objects-spacing', '--functions-spacing', '-i'],
\ 'replace': 1,
\ 'stderr': 1,
\ 'stdin': 0
\ }
endfunction
+6 -2
View File
@@ -1,7 +1,7 @@
local gen_hook = MiniSplitjoin.gen_hook
local curly = { brackets = { '%b{}' }, separator = ';' }
local curly_semi = { brackets = { '%b{}' }, separator = ';' }
local curly = { brackets = { "%b{}" }, separator = ";" }
local curly_semi = { brackets = { "%b{}" }, separator = ";" }
local add_semicolon_curly = gen_hook.add_trailing_separator(curly)
local remove_semicolon_curly = gen_hook.del_trailing_separator(curly)
local pad_curly = gen_hook.pad_brackets(curly_semi)
@@ -10,3 +10,7 @@ vim.b.minisplitjoin_config = {
split = { hooks_post = { remove_semicolon_curly } },
join = { hooks_pre = { add_semicolon_curly }, hooks_post = { pad_curly } },
}
vim.keymap.set("n", "gd", function()
require("functions.smart_jump").smart_qml_jump()
end, { buffer = bufnr, silent = true, desc = "Smart QML jump" })
+1 -1
View File
@@ -40,4 +40,4 @@ vim.filetype.add {
},
}
vim.cmd "colorscheme tokyonight"
require "config.load-colorscheme"
+55
View File
@@ -27,3 +27,58 @@ autocmd({ "InsertLeave" }, {
require("lint").try_lint()
end,
})
local progress = vim.defaulttable()
vim.api.nvim_create_autocmd("LspProgress", {
---@param ev {data: {client_id: integer, params: lsp.ProgressParams}}
callback = function(ev)
local client = vim.lsp.get_client_by_id(ev.data.client_id)
local value = ev.data.params.value --[[@as {percentage?: number, title?: string, message?: string, kind: "begin" | "report" | "end"}]]
if not client or type(value) ~= "table" then
return
end
local p = progress[client.id]
for i = 1, #p + 1 do
if i == #p + 1 or p[i].token == ev.data.params.token then
p[i] = {
token = ev.data.params.token,
msg = ("[%3d%%] %s%s"):format(
value.kind == "end" and 100 or value.percentage or 100,
value.title or "",
value.message and (" **%s**"):format(value.message)
or ""
),
done = value.kind == "end",
}
break
end
end
local msg = {} ---@type string[]
progress[client.id] = vim.tbl_filter(function(v)
return table.insert(msg, v.msg) or not v.done
end, p)
local spinner = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
vim.notify(table.concat(msg, "\n"), "info", {
id = "lsp_progress",
title = client.name,
opts = function(notif)
notif.icon = #progress[client.id] == 0 and ""
or spinner[math.floor(vim.uv.hrtime() / (1e6 * 80)) % #spinner + 1]
end,
})
end,
})
+85 -37
View File
@@ -1,4 +1,4 @@
vimiopt.backup = false
vim.opt.backup = false
vim.opt.writebackup = false
vim.opt.completeopt = "menuone,menu,noinsert,noselect,popup"
vim.opt.pumheight = 10
@@ -9,8 +9,8 @@ vim.opt.signcolumn = "yes"
local keyset = vim.keymap.set
function _G.check_back_space()
local col = vim.fn.col('.') - 1
return col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') ~= nil
local col = vim.fn.col "." - 1
return col == 0 or vim.fn.getline("."):sub(col, col):match "%s" ~= nil
end
-- Use Tab for trigger completion with characters ahead and navigate
@@ -18,14 +18,25 @@ end
-- no select by setting `"suggest.noselect": true` in your configuration file
-- NOTE: Use command ':verbose imap <tab>' to make sure Tab is not mapped by
-- other plugins before putting this into your config
local opts = {silent = true, noremap = true, expr = true, replace_keycodes = false}
keyset("i", "<TAB>", 'coc#pum#visible() ? coc#pum#next(0) : v:lua.check_back_space() ? "<TAB>" : coc#refresh()', opts)
local opts =
{ silent = true, noremap = true, expr = true, replace_keycodes = false }
keyset(
"i",
"<TAB>",
'coc#pum#visible() ? coc#pum#next(0) : v:lua.check_back_space() ? "<TAB>" : coc#refresh()',
opts
)
keyset("i", "<S-TAB>", [[coc#pum#visible() ? coc#pum#prev(0) : "\<C-h>"]], opts)
-- Make <CR> to accept selected completion item or notify coc.nvim to format
-- <C-g>u breaks current undo, please make your own choice
keyset("i", "<cr>", [[coc#pum#visible() ? coc#pum#confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"]], opts)
keyset(
"i",
"<cr>",
[[coc#pum#visible() ? coc#pum#confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"]],
opts
)
-- Use <c-j> to trigger snippets
keyset("i", "<c-j>", "<Plug>(coc-snippets-expand-jump)")
@@ -43,45 +54,40 @@ keyset("n", "gy", "<Plug>(coc-type-definition)", {silent = true})
keyset("n", "gi", "<Plug>(coc-implementation)", { silent = true })
keyset("n", "gr", "<Plug>(coc-references)", { silent = true })
-- Use K to show documentation in preview window
function _G.show_docs()
local cw = vim.fn.expand('<cword>')
if vim.fn.index({'vim', 'help'}, vim.bo.filetype) >= 0 then
vim.api.nvim_command('h ' .. cw)
elseif vim.api.nvim_eval('coc#rpc#ready()') then
vim.fn.CocActionAsync('doHover')
local cw = vim.fn.expand "<cword>"
if vim.fn.index({ "vim", "help" }, vim.bo.filetype) >= 0 then
vim.api.nvim_command("h " .. cw)
elseif vim.api.nvim_eval "coc#rpc#ready()" then
vim.fn.CocActionAsync "doHover"
else
vim.api.nvim_command('!' .. vim.o.keywordprg .. ' ' .. cw)
vim.api.nvim_command("!" .. vim.o.keywordprg .. " " .. cw)
end
end
keyset("n", "K", '<CMD>lua _G.show_docs()<CR>', {silent = true})
keyset("n", "K", "<CMD>lua _G.show_docs()<CR>", { silent = true })
-- Highlight the symbol and its references on a CursorHold event(cursor is idle)
vim.api.nvim_create_augroup("CocGroup", {})
vim.api.nvim_create_autocmd("CursorHold", {
group = "CocGroup",
command = "silent call CocActionAsync('highlight')",
desc = "Highlight symbol under cursor on CursorHold"
desc = "Highlight symbol under cursor on CursorHold",
})
-- Symbol renaming
keyset("n", "<leader>rn", "<Plug>(coc-rename)", { silent = true })
-- Formatting selected code
keyset("x", "<leader>f", "<Plug>(coc-format-selected)", { silent = true })
keyset("n", "<leader>f", "<Plug>(coc-format-selected)", { silent = true })
-- Setup formatexpr specified filetype(s)
vim.api.nvim_create_autocmd("FileType", {
group = "CocGroup",
pattern = "typescript,json",
command = "setl formatexpr=CocAction('formatSelected')",
desc = "Setup formatexpr specified filetype(s)."
desc = "Setup formatexpr specified filetype(s).",
})
-- Apply codeAction to the selected region
@@ -99,13 +105,22 @@ keyset("n", "<leader>qf", "<Plug>(coc-fix-current)", opts)
-- Remap keys for apply refactor code actions.
keyset("n", "<leader>re", "<Plug>(coc-codeaction-refactor)", { silent = true })
keyset("x", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
keyset("n", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
keyset(
"x",
"<leader>r",
"<Plug>(coc-codeaction-refactor-selected)",
{ silent = true }
)
keyset(
"n",
"<leader>r",
"<Plug>(coc-codeaction-refactor-selected)",
{ silent = true }
)
-- Run the Code Lens actions on the current line
keyset("n", "<leader>cl", "<Plug>(coc-codelens-action)", opts)
-- Map function and class text objects
-- NOTE: Requires 'textDocument.documentSymbol' support from the language server
keyset("x", "if", "<Plug>(coc-funcobj-i)", opts)
@@ -117,39 +132,72 @@ keyset("o", "ic", "<Plug>(coc-classobj-i)", opts)
keyset("x", "ac", "<Plug>(coc-classobj-a)", opts)
keyset("o", "ac", "<Plug>(coc-classobj-a)", opts)
-- Remap <C-f> and <C-b> to scroll float windows/popups
---@diagnostic disable-next-line: redefined-local
local opts = { silent = true, nowait = true, expr = true }
keyset("n", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
keyset("n", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
keyset("i", "<C-f>",
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(1)<cr>" : "<Right>"', opts)
keyset("i", "<C-b>",
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(0)<cr>" : "<Left>"', opts)
keyset("v", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
keyset("v", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
keyset(
"n",
"<C-f>",
'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"',
opts
)
keyset(
"n",
"<C-b>",
'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"',
opts
)
keyset(
"i",
"<C-f>",
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(1)<cr>" : "<Right>"',
opts
)
keyset(
"i",
"<C-b>",
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(0)<cr>" : "<Left>"',
opts
)
keyset(
"v",
"<C-f>",
'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"',
opts
)
keyset(
"v",
"<C-b>",
'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"',
opts
)
-- Use CTRL-S for selections ranges
-- Requires 'textDocument/selectionRange' support of language server
keyset("n", "<C-s>", "<Plug>(coc-range-select)", { silent = true })
keyset("x", "<C-s>", "<Plug>(coc-range-select)", { silent = true })
-- Add `:Format` command to format current buffer
vim.api.nvim_create_user_command("Format", "call CocAction('format')", {})
-- " Add `:Fold` command to fold current buffer
vim.api.nvim_create_user_command("Fold", "call CocAction('fold', <f-args>)", {nargs = '?'})
vim.api.nvim_create_user_command(
"Fold",
"call CocAction('fold', <f-args>)",
{ nargs = "?" }
)
-- Add `:OR` command for organize imports of the current buffer
vim.api.nvim_create_user_command("OR", "call CocActionAsync('runCommand', 'editor.action.organizeImport')", {})
vim.api.nvim_create_user_command(
"OR",
"call CocActionAsync('runCommand', 'editor.action.organizeImport')",
{}
)
-- Add (Neo)Vim's native statusline support
-- NOTE: Please see `:h coc-status` for integrations with external plugins that
-- provide custom statusline: lightline.vim, vim-airline
vim.opt.statusline:prepend("%{coc#status()}%{get(b:,'coc_current_function','')}")
vim.opt.statusline:prepend "%{coc#status()}%{get(b:,'coc_current_function','')}"
-- Mappings for CoCList
-- code actions and coc stuff
+4 -4
View File
@@ -1,9 +1,9 @@
---@diagnostic disable: redundant-parameter
require("catppuccin").setup({
flavour = "auto",
require("catppuccin").setup {
flavour = "latte",
background = {
light = "latte",
dark = "mocha",
dark = "latte",
},
transparent_background = false,
float = {
@@ -68,4 +68,4 @@ require("catppuccin").setup({
indentscope_color = "",
},
},
})
}
+18
View File
@@ -0,0 +1,18 @@
local M = {}
M = {
keymaps = {
toggle = "<C-S-q>",
quit = nil,
},
border = "rounded",
width = "0.8",
height = "0.8",
model = "gpt-5.2",
autoinstall = false,
panel = false,
use_buffer = false,
}
return M
+2
View File
@@ -0,0 +1,2 @@
vim.cmd.colorscheme "tokyodark"
vim.o.background = "dark"
+79 -6
View File
@@ -1,3 +1,7 @@
local cmp = require "cmp"
local cmp_lsp = require "cmp_nvim_lsp"
local cmp_kinds = require("assets.icons").icons.kinds
local function flatten_to_array(t)
local res = {}
local function _flatten(tbl)
@@ -17,7 +21,7 @@ local capabilities = vim.tbl_deep_extend(
"force",
{},
vim.lsp.protocol.make_client_capabilities(),
require("blink.cmp").get_lsp_capabilities()
cmp_lsp.default_capabilities()
)
require("fidget").setup {}
@@ -94,6 +98,74 @@ require("mason-lspconfig").setup {
},
}
cmp.setup {
preselect = "None",
formatting = {
fields = { "kind", "abbr" },
format = function(entry, vim_item)
vim_item.kind = cmp_kinds[vim_item.kind] or ""
if entry.completion_item.detail then
vim_item.menu = entry.completion_item.detail
end
return vim_item
end,
},
completion = { completeopt = "menu,menuone" },
snippet = {
expand = function(args)
require("luasnip").lsp_expand(args.body)
end,
},
window = {
completion = cmp.config.window.bordered(),
documentation = cmp.config.window.bordered(),
},
view = {
entries = "custom",
},
mapping = {
["<C-p>"] = cmp.mapping.select_prev_item(),
["<C-n>"] = cmp.mapping.select_next_item(),
["<C-d>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.close(),
["<CR>"] = cmp.mapping.confirm {
behavior = cmp.ConfirmBehavior.Insert,
select = true,
},
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif require("luasnip").expand_or_jumpable() then
require("luasnip").expand_or_jump()
else
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif require("luasnip").jumpable(-1) then
require("luasnip").jump(-1)
else
fallback()
end
end, { "i", "s" }),
},
sources = cmp.config.sources {
{ name = "path" },
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "buffer" },
{ name = "nvim_lua" },
},
}
vim.diagnostic.config {
virtual_text = false,
virtual_lines = false,
@@ -165,6 +237,12 @@ lspconfig("texlab", {
lspconfig("qmlls", {
cmd = { "qmlls6" },
filetypes = { "qml" },
single_file_support = true,
root_dir = function(bufnr, on_dir)
local root = vim.fs.root(bufnr, ".git")
on_dir(root)
end,
})
lspconfig("jsonls", {
@@ -210,11 +288,6 @@ for _, server in ipairs(flat_servers) do
if client.name == "typos_lsp" then
return
end
require("workspace-diagnostics").populate_workspace_diagnostics(
client,
bufnr
)
end,
capabilities = capabilities,
})
+56 -89
View File
@@ -1,7 +1,7 @@
vim.notify = require('notify')
local dap = require('dap')
vim.notify = require "notify"
local dap = require "dap"
require('notify').setup({
require("notify").setup {
render = "wrapped-default",
timeout = 6000,
max_width = 50,
@@ -17,9 +17,9 @@ require('notify').setup({
},
on_open = function(win)
-- vim.api.nvim_win_set_option(win, 'wrap', true)
vim.api.nvim_win_set_option(win, 'breakat', ' ')
vim.api.nvim_win_set_option(win, "breakat", " ")
end,
})
}
-- Utility functions shared between progress reports for LSP and DAP
@@ -37,8 +37,8 @@ local function get_notif_data(client_id, token)
return client_notifs[client_id][token]
end
local spinner_frames = { "", "", "", "", "", "", "", "" }
local spinner_frames =
{ "", "", "", "", "", "", "", "" }
local function update_spinner(client_id, token)
local notif_data = get_notif_data(client_id, token)
@@ -67,85 +67,52 @@ local function format_message(message, percentage)
return (percentage and percentage .. "%\t" or "") .. (message or "")
end
-- vim.lsp.handlers["$/progress"] = function(_, result, ctx)
-- local client_id = ctx.client_id
--
-- local val = result.value
--
-- if not val.kind then
-- return
-- end
--
-- local notif_data = get_notif_data(client_id, result.token)
--
-- if val.kind == "begin" then
-- local message = format_message(val.message, val.percentage)
--
-- notif_data.notification = vim.notify(message, "info", {
-- title = format_title(val.title, vim.lsp.get_client_by_id(client_id).name),
-- icon = spinner_frames[1],
-- timeout = false,
-- hide_from_history = false,
-- })
--
-- notif_data.spinner = 1
-- update_spinner(client_id, result.token)
-- elseif val.kind == "report" and notif_data then
-- notif_data.notification = vim.notify(format_message(val.message, val.percentage), "info", {
-- replace = notif_data.notification,
-- hide_from_history = false,
-- })
-- elseif val.kind == "end" and notif_data then
-- notif_data.notification =
-- vim.notify(val.message and format_message(val.message) or "Complete", "info", {
-- icon = "",
-- replace = notif_data.notification,
-- timeout = 6000,
-- })
--
-- notif_data.spinner = nil
-- end
-- end
--
-- local severity = {
-- "error",
-- "warn",
-- "info",
-- "info", -- map both hint and info to info?
-- }
-- vim.lsp.handlers["window/showMessage"] = function(err, method, params, client_id)
-- vim.notify(method.message, severity[params.type])
-- end
--
-- dap.listeners.before['event_progressStart']['progress-notifications'] = function(session, body)
-- local notif_data = get_notif_data("dap", body.progressId)
--
-- local message = format_message(body.message, body.percentage)
-- notif_data.notification = vim.notify(message, "info", {
-- title = format_title(body.title, session.config.type),
-- icon = spinner_frames[1],
-- timeout = false,
-- hide_from_history = false,
-- })
--
-- notif_data.notification.spinner = 1,
-- update_spinner("dap", body.progressId)
-- end
--
-- dap.listeners.before['event_progressUpdate']['progress-notifications'] = function(session, body)
-- local notif_data = get_notif_data("dap", body.progressId)
-- notif_data.notification = vim.notify(format_message(body.message, body.percentage), "info", {
-- replace = notif_data.notification,
-- hide_from_history = false,
-- })
-- end
--
-- dap.listeners.before['event_progressEnd']['progress-notifications'] = function(session, body)
-- local notif_data = client_notifs["dap"][body.progressId]
-- notif_data.notification = vim.notify(body.message and format_message(body.message) or "Complete", "info", {
-- icon = "",
-- replace = notif_data.notification,
-- timeout = 6000
-- })
-- notif_data.spinner = nil
-- end
-- LSP integration
-- Make sure to also have the snippet with the common helper functions in your config!
vim.lsp.handlers["$/progress"] = function(_, result, ctx)
local client_id = ctx.client_id
local val = result.value
if not val.kind then
return
end
local notif_data = get_notif_data(client_id, result.token)
if val.kind == "begin" then
local message = format_message(val.message, val.percentage)
notif_data.notification = vim.notify(message, "info", {
title = format_title(
val.title,
vim.lsp.get_client_by_id(client_id).name
),
icon = spinner_frames[1],
timeout = false,
hide_from_history = false,
})
notif_data.spinner = 1
update_spinner(client_id, result.token)
elseif val.kind == "report" and notif_data then
notif_data.notification =
vim.notify(format_message(val.message, val.percentage), "info", {
replace = notif_data.notification,
hide_from_history = false,
})
elseif val.kind == "end" and notif_data then
notif_data.notification = vim.notify(
val.message and format_message(val.message) or "Complete",
"info",
{
icon = "",
replace = notif_data.notification,
timeout = 3000,
}
)
notif_data.spinner = nil
end
end
+55
View File
@@ -0,0 +1,55 @@
local opts = {}
opts = {
file_types = { "markdown" },
completions = {
lsp = {
enabled = true,
},
},
render_modes = true,
anti_conceal = {
enabled = true,
above = 1,
below = 1,
},
code = {
enabled = true,
render_modes = false,
sign = true,
conceal_delimiters = true,
language = true,
position = "left",
language_icon = true,
language_name = true,
language_info = true,
language_pad = 0,
width = "full",
left_margin = 0,
left_pad = 2,
right_pad = 0,
min_width = 40,
border = "thick",
language_border = "",
language_left = "",
language_right = "",
above = "",
below = "",
inline = true,
inline_left = "",
inline_right = "",
inline_pad = 0,
priority = 140,
highlight = "RenderMarkdownCode",
highlight_info = "RenderMarkdownCodeInfo",
highlight_language = nil,
highlight_border = "RenderMarkdownCodeBorder",
highlight_fallback = "RenderMarkdownCodeFallback",
highlight_inline = "RenderMarkdownCodeInline",
style = "full",
},
}
return opts
+22
View File
@@ -0,0 +1,22 @@
require("smart-splits").setup {
ignored_buftypes = {
"nofile",
"quickfix",
"prompt",
},
ignored_filetypes = { "NvimTree" },
default_amount = 3,
at_edge = "wrap",
float_win_behavior = "previous",
move_cursor_same_row = false,
cursor_follows_swapped_bufs = false,
ignored_events = {
"BufEnter",
"WinEnter",
},
multiplexer_integration = nil,
disable_multiplexer_nav_when_zoomed = true,
kitty_password = nil,
zellij_move_focus_or_tab = false,
log_level = "error",
}
+56 -5
View File
@@ -57,7 +57,33 @@ return {
max_height = 80,
},
},
notifier = { enabled = true },
notifier = {
timeout = 3000,
width = { min = 40, max = 0.4 },
height = { min = 1, max = 0.6 },
margin = { top = 0, right = 1, bottom = 0 },
padding = true,
gap = 0,
sort = { "level", "added" },
level = vim.log.levels.TRACE,
icons = {
error = "",
warn = "",
info = "",
debug = "",
trace = "",
},
keep = function(notif)
return vim.fn.getcmdpos() > 0
end,
---@type snacks.notifier.style
style = "fancy",
top_down = true,
date_format = "%R",
---@type string|boolean
more_format = " ↓ %d lines ",
refresh = 50,
},
quickfile = { enabled = true },
scope = { enabled = true },
scroll = { enabled = false },
@@ -75,10 +101,35 @@ return {
function()
Snacks.terminal.toggle()
end,
mode = "t"
}
}
}
mode = "t",
},
},
},
notification = {
border = true,
zindex = 100,
ft = "markdown",
wo = {
winblend = 0,
wrap = true,
conceallevel = 2,
colorcolumn = "",
},
bo = { filetype = "snacks_notif" },
},
notification_history = {
border = true,
zindex = 100,
minimal = false,
title = " Notifications ",
title_pos = "center",
ft = "markdown",
bo = { filetype = "snacks_notif_history", modifiable = false },
wo = { winhighlight = "Normal:SnacksNotifierHistory" },
keys = { q = "close" },
},
},
gitbrowse = {
enabled = true,
+202
View File
@@ -0,0 +1,202 @@
local M = {}
local function get_qmlls_client(bufnr)
for _, c in ipairs(vim.lsp.get_clients { bufnr = bufnr }) do
if c.name == "qmlls" then
return c
end
end
end
local function first_client_encoding(bufnr)
local c = vim.lsp.get_clients({ bufnr = bufnr })[1]
return (c and c.offset_encoding) or "utf-16"
end
local function normalize_locations(result)
if not result then
return {}
end
-- Single Location / LocationLink
if result.uri or result.targetUri then
return { result }
end
-- Array of Location / LocationLink
if vim.islist(result) then
return result
end
return {}
end
local function request_locations(bufnr, method, timeout_ms)
local enc = first_client_encoding(bufnr)
local params = vim.lsp.util.make_position_params(0, enc)
local responses =
vim.lsp.buf_request_sync(bufnr, method, params, timeout_ms or 1000)
if not responses then
return {}
end
local all = {}
for client_id, resp in pairs(responses) do
local result = resp and resp.result
local locs = normalize_locations(result)
for _, loc in ipairs(locs) do
table.insert(all, { client_id = client_id, loc = loc })
end
end
return all
end
local function jump_to_first_location(bufnr, matches)
if #matches == 0 then
return false
end
local m = matches[1]
local client = vim.lsp.get_client_by_id(m.client_id)
local enc = (client and client.offset_encoding)
or first_client_encoding(bufnr)
local loc = m.loc
-- Convert LocationLink -> Location-ish target for jump_to_location
if loc.targetUri then
loc = {
uri = loc.targetUri,
range = loc.targetSelectionRange or loc.targetRange,
}
end
vim.lsp.util.jump_to_location(loc, enc)
return true
end
local function get_cursor_context(bufnr)
local pos = vim.api.nvim_win_get_cursor(0)
local row = pos[1] - 1
local col = pos[2]
local line = vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] or ""
local cword = vim.fn.expand "<cword>"
return row, col, line, cword
end
-- Tries to detect something like Config.save() and returns ("Config", "save")
local function detect_singleton_member_call(bufnr)
local _, col, line, cword = get_cursor_context(bufnr)
local before = line:sub(1, col + 1)
-- If cursor is on "save" in Config.save(), this usually works.
local singleton = before:match "([%a_][%w_]*)%s*%.[%w_]*$"
if not singleton then
-- If cursor is on "Config", this can also catch it.
singleton = before:match "([%a_][%w_]*)%s*$"
if singleton and not line:sub(col + 1):match "^%s*%." then
singleton = nil
end
end
if not singleton then
return nil
end
-- Basic heuristic: singleton names are often capitalized in QML
-- (you can remove this check if your singletons are lowercase)
if not singleton:match "^[A-Z_]" then
return nil
end
return singleton, cword
end
local function find_project_root(bufnr)
local qmlls = get_qmlls_client(bufnr)
if qmlls and qmlls.config and qmlls.config.root_dir then
return qmlls.config.root_dir
end
return vim.fs.root(bufnr, { ".qmlls.ini", ".git" }) or vim.fn.getcwd()
end
local function singleton_fallback_jump(bufnr)
local singleton, member = detect_singleton_member_call(bufnr)
if not singleton then
return false
end
local root = find_project_root(bufnr)
local target_name = singleton .. ".qml"
local matches = vim.fs.find(target_name, {
path = root,
type = "file",
limit = math.huge,
})
if not matches or vim.tbl_isempty(matches) then
return false
end
local pick = nil
if #matches == 1 then
pick = matches[1]
else
-- Prefer a path containing "/Config/" for Config.qml, etc.
for _, p in ipairs(matches) do
if
p:match("/" .. singleton .. "/")
or p:match("/" .. target_name .. "$")
then
pick = p
break
end
end
pick = pick or matches[1]
end
vim.cmd.edit(vim.fn.fnameescape(pick))
-- Optional: try to jump near the member inside the singleton file.
if member and member ~= singleton then
local escaped = vim.fn.escape(member, [[\/]])
-- Try function save(...) first, then any "save" occurrence.
local found =
vim.fn.search("\\<function\\s\\+" .. escaped .. "\\s*(", "W")
if found == 0 then
vim.fn.search("\\<" .. escaped .. "\\>", "W")
end
end
vim.notify(
("LSP returned no locations; fell back to %s.qml"):format(singleton),
vim.log.levels.INFO
)
return true
end
function M.smart_qml_jump()
local bufnr = vim.api.nvim_get_current_buf()
-- 1) Try normal definition
local defs = request_locations(bufnr, "textDocument/definition", 1200)
if jump_to_first_location(bufnr, defs) then
return
end
-- 2) Try type definition
local tdefs = request_locations(bufnr, "textDocument/typeDefinition", 1200)
if jump_to_first_location(bufnr, tdefs) then
return
end
-- 3) Singleton fallback: Config.save() -> Config.qml
if singleton_fallback_jump(bufnr) then
return
end
vim.notify(
"No locations found (definition/typeDefinition/fallback)",
vim.log.levels.WARN
)
end
return M
+18
View File
@@ -14,6 +14,16 @@ map("n", "<A-c>", vim.cmd.CopilotChatToggle)
map("i", "<A-c>", vim.cmd.CopilotChatToggle)
map("v", "<A-c>", vim.cmd.CopilotChatToggle)
-- Splits
vim.keymap.set("n", "<A-S-Left>", require("smart-splits").resize_left)
vim.keymap.set("n", "<A-S-Down>", require("smart-splits").resize_down)
vim.keymap.set("n", "<A-S-Up>", require("smart-splits").resize_up)
vim.keymap.set("n", "<A-S-Right>", require("smart-splits").resize_right)
vim.keymap.set("n", "<A-Left>", require("smart-splits").move_cursor_left)
vim.keymap.set("n", "<A-Down>", require("smart-splits").move_cursor_down)
vim.keymap.set("n", "<A-Up>", require("smart-splits").move_cursor_up)
vim.keymap.set("n", "<A-Right>", require("smart-splits").move_cursor_right)
-- Explorer and Undotree
map("n", "<leader>e", function()
Snacks.explorer()
@@ -39,6 +49,14 @@ map(
{ desc = "Telescope find files" }
)
-- LSP
map(
"n",
"gd",
vim.lsp.buf.definition,
{ noremap = true, silent = true, buffer = bufnr }
)
map("n", "<A-->", ":bdelete<CR>")
-- map("n", "<SA-->", ":BufferRestore<CR>")
+4 -3
View File
@@ -18,9 +18,10 @@ return {
{
"catppuccin/nvim",
name = "catppuccin",
-- config = function()
-- require("config.catppuccin")
-- end,
priority = 1000,
config = function()
require "config.catppuccin"
end,
},
{
"rebelot/kanagawa.nvim",
+66 -36
View File
@@ -80,12 +80,6 @@ return {
{
"tpope/vim-fugitive",
},
{
"rcarriga/nvim-notify",
config = function()
require "config.notify"
end,
},
{
"zbirenbaum/copilot.lua",
lazy = true,
@@ -128,11 +122,15 @@ return {
dependencies = {
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim",
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"hrsh7th/cmp-cmdline",
"hrsh7th/nvim-cmp",
"L3MON4D3/LuaSnip",
-- "saadparwaiz1/cmp_luasnip",
"saadparwaiz1/cmp_luasnip",
"j-hui/fidget.nvim",
"b0o/schemastore.nvim",
"saghen/blink.cmp",
},
config = function()
require "config.lspconfig"
@@ -211,28 +209,28 @@ return {
vim.g.minimal_italic_functions = true
end,
},
{
"propet/colorscheme-persist.nvim",
dependencies = {
"nvim-telescope/telescope.nvim",
},
lazy = false,
config = true,
keys = {
{
"<leader>sp",
function()
require("colorscheme-persist").picker()
end,
mode = "n",
},
},
opts = {
picker_opts = require("telescope.themes").get_dropdown {
enable_preview = true,
},
},
},
-- {
-- "propet/colorscheme-persist.nvim",
-- dependencies = {
-- "nvim-telescope/telescope.nvim",
-- },
-- lazy = false,
-- config = true,
-- keys = {
-- {
-- "<leader>sp",
-- function()
-- require("colorscheme-persist").picker()
-- end,
-- mode = "n",
-- },
-- },
-- opts = {
-- picker_opts = require("telescope.themes").get_dropdown {
-- enable_preview = true,
-- },
-- },
-- },
{
"aznhe21/actions-preview.nvim",
config = function()
@@ -254,9 +252,9 @@ return {
{
"MunifTanjim/nui.nvim",
},
{
"artemave/workspace-diagnostics.nvim",
},
-- {
-- "artemave/workspace-diagnostics.nvim",
-- },
{
require "config.dev-tools",
},
@@ -272,9 +270,6 @@ return {
{
require "config.dropbar",
},
{
require "config.blink",
},
{
"lewis6991/gitsigns.nvim",
config = function()
@@ -299,8 +294,43 @@ return {
},
{
"Zacharias-Brohn/zterm-navigator.nvim",
enabled = false,
config = function()
require "config.zterm-navigator"
end,
},
{
"MeanderingProgrammer/render-markdown.nvim",
dependencies = {
"nvim-treesitter/nvim-treesitter",
"nvim-mini/mini.nvim",
},
---@module 'render-markdown'
---@type render.md.UserConfig
opts = require "config.render-markdown",
},
{
"mrjones2014/smart-splits.nvim",
config = function()
require "config.smart-splits"
end,
},
{
"kkrampis/codex.nvim",
lazy = true,
cmd = { "Codex", "CodexToggle" },
keys = {
-- {
-- nil,
-- function()
-- require("codex").toggle()
-- end,
-- desc = "Toggle Codex",
-- mode = { "n", "t" },
-- },
},
opts = function()
require "config.codex"
end,
},
}
+1
View File
@@ -8,3 +8,4 @@ let g:neoformat_enabled_lua = ['stylua']
let g:neoformat_enabled_rust = ['rustfmt']
let g:neoformat_enabled_cpp = ['uncrustify']
let g:neoformat_enabled_markdown = ['prettier']
let g:neoformat_enabled_qml = ['qmlformat']