2023-11-23 21:27:17 +01:00
|
|
|
|
local M = {}
|
2024-03-10 16:47:43 +01:00
|
|
|
|
|
|
|
|
|
function M.lsp_on_attach(client, bufnr)
|
|
|
|
|
-- TODO: Check this on 0.10.0 release
|
|
|
|
|
if client.supports_method("textDocument/semanticTokens/full") and vim.lsp.semantic_tokens then
|
|
|
|
|
vim.b[bufnr].semantic_tokens_enabled = true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if client.supports_method("textDocument/documentHighlight") then
|
|
|
|
|
M.add_buffer_autocmd("lsp_document_highlight", bufnr, {
|
|
|
|
|
{
|
|
|
|
|
events = { "CursorHold", "CursorHoldI" },
|
|
|
|
|
desc = "highlight references when cursor holds",
|
|
|
|
|
callback = function()
|
|
|
|
|
if not M.has_capability("textDocument/documentHighlight", { bufnr = bufnr }) then
|
|
|
|
|
M.del_buffer_autocmd("lsp_document_highlight", bufnr)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
vim.lsp.buf.document_highlight()
|
|
|
|
|
end,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
events = { "CursorMoved", "CursorMovedI", "BufLeave" },
|
|
|
|
|
desc = "clear references when cursor moves",
|
|
|
|
|
callback = function()
|
|
|
|
|
vim.lsp.buf.clear_references()
|
|
|
|
|
end,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if client.supports_method("textDocument/inlayHint") then
|
|
|
|
|
if vim.b[bufnr].inlay_hints_enabled == nil then
|
|
|
|
|
vim.b[bufnr].inlay_hints_enabled = true
|
|
|
|
|
end
|
|
|
|
|
-- TODO: Check this on 0.10.0 release
|
|
|
|
|
if vim.lsp.inlay_hint and vim.b[bufnr].inlay_hints_enabled then
|
|
|
|
|
vim.lsp.inlay_hint.enable(bufnr, true)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- TODO: Check this on 0.10.0 release
|
|
|
|
|
if vim.lsp.inlay_hint and vim.b[bufnr].inlay_hints_enabled then
|
|
|
|
|
vim.lsp.inlay_hint.enable(bufnr, true)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local maps = require("config.keymaps").lsp_maps(client, bufnr)
|
|
|
|
|
M.set_maps(maps, { buffer = bufnr })
|
|
|
|
|
end
|
2023-11-23 21:27:17 +01:00
|
|
|
|
|
|
|
|
|
function M.set_title()
|
2024-03-10 14:31:09 +01:00
|
|
|
|
local title = " %t"
|
|
|
|
|
local f = io.popen([[ zsh -lc 'print -P $PS1' | sed 's/\[[0-9;]*m//g;s/» / %t/g' ]])
|
|
|
|
|
if f ~= nil then
|
|
|
|
|
title = f:read("*a") or ""
|
|
|
|
|
f:close()
|
|
|
|
|
end
|
|
|
|
|
vim.opt.titlestring = title
|
2023-11-23 21:27:17 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-01-24 00:48:37 +01:00
|
|
|
|
function M.buf_close(bufnr, force)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
local kill_command = "bd"
|
|
|
|
|
|
|
|
|
|
local bo = vim.bo
|
|
|
|
|
local api = vim.api
|
|
|
|
|
local fnamemodify = vim.fn.fnamemodify
|
|
|
|
|
|
|
|
|
|
if bufnr == 0 or bufnr == nil then
|
|
|
|
|
bufnr = api.nvim_get_current_buf()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local bufname = api.nvim_buf_get_name(bufnr)
|
|
|
|
|
|
|
|
|
|
if not force then
|
|
|
|
|
local warning
|
|
|
|
|
if bo[bufnr].modified then
|
|
|
|
|
warning = string.format([[No write since last change for (%s)]], fnamemodify(bufname, ":t"))
|
|
|
|
|
elseif api.nvim_buf_get_option(bufnr, "buftype") == "terminal" then
|
|
|
|
|
warning = string.format([[Terminal %s will be killed]], bufname)
|
|
|
|
|
end
|
|
|
|
|
if warning then
|
|
|
|
|
vim.ui.input({
|
|
|
|
|
prompt = string.format([[%s. Close it anyway? [y]es or [n]o (default: no): ]], warning),
|
|
|
|
|
}, function(choice)
|
|
|
|
|
if choice:match("ye?s?") then
|
|
|
|
|
force = true
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
if not force then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Get list of window IDs with the buffer to close
|
|
|
|
|
local windows = vim.tbl_filter(function(win)
|
|
|
|
|
return api.nvim_win_get_buf(win) == bufnr
|
|
|
|
|
end, api.nvim_list_wins())
|
|
|
|
|
|
|
|
|
|
if #windows == 0 then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if force then
|
|
|
|
|
kill_command = kill_command .. "!"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Get list of active buffers
|
|
|
|
|
local buffers = vim.tbl_filter(function(buf)
|
|
|
|
|
return api.nvim_buf_is_valid(buf) and bo[buf].buflisted
|
|
|
|
|
end, api.nvim_list_bufs())
|
|
|
|
|
|
|
|
|
|
-- If there is only one buffer (which has to be the current one), vim will
|
|
|
|
|
-- create a new buffer on :bd.
|
|
|
|
|
-- For more than one buffer, pick the previous buffer (wrapping around if necessary)
|
|
|
|
|
if #buffers > 1 then
|
|
|
|
|
for i, v in ipairs(buffers) do
|
|
|
|
|
if v == bufnr then
|
|
|
|
|
local prev_buf_idx = i == 1 and (#buffers - 1) or (i - 1)
|
|
|
|
|
local prev_buffer = buffers[prev_buf_idx]
|
|
|
|
|
for _, win in ipairs(windows) do
|
|
|
|
|
api.nvim_win_set_buf(win, prev_buffer)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
vim.cmd("q!")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Check if buffer still exists, to ensure the target buffer wasn't killed
|
|
|
|
|
-- due to options like bufhidden=wipe.
|
|
|
|
|
if api.nvim_buf_is_valid(bufnr) and bo[bufnr].buflisted then
|
|
|
|
|
vim.cmd(string.format("%s %d", kill_command, bufnr))
|
|
|
|
|
end
|
2024-01-24 00:48:37 +01:00
|
|
|
|
end
|
2023-11-23 21:27:17 +01:00
|
|
|
|
|
2024-01-24 00:48:37 +01:00
|
|
|
|
function M.is_available(plugin)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
local lazy_config_avail, lazy_config = pcall(require, "lazy.core.config")
|
|
|
|
|
return lazy_config_avail and lazy_config.spec.plugins[plugin] ~= nil
|
2024-01-24 00:48:37 +01:00
|
|
|
|
end
|
2023-11-23 21:27:17 +01:00
|
|
|
|
|
2024-01-24 00:48:37 +01:00
|
|
|
|
function M.empty_map_table()
|
2024-03-10 14:31:09 +01:00
|
|
|
|
local maps = {}
|
|
|
|
|
for _, mode in ipairs({ "", "n", "v", "x", "s", "o", "!", "i", "l", "c", "t" }) do
|
|
|
|
|
maps[mode] = {}
|
|
|
|
|
end
|
|
|
|
|
-- TODO: Check this on 0.10.0 release
|
|
|
|
|
if vim.fn.has("nvim-0.10.0") == 1 then
|
|
|
|
|
for _, abbr_mode in ipairs({ "ia", "ca", "!a" }) do
|
|
|
|
|
maps[abbr_mode] = {}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return maps
|
2024-01-24 00:48:37 +01:00
|
|
|
|
end
|
2023-11-23 21:27:17 +01:00
|
|
|
|
|
2024-01-24 00:48:37 +01:00
|
|
|
|
function M.toggle_term_cmd(opts)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
if not vim.g.user_terminals then
|
|
|
|
|
vim.g.user_terminals = {}
|
|
|
|
|
end
|
|
|
|
|
local terms = vim.g.user_terminals
|
|
|
|
|
if type(opts) == "string" then
|
|
|
|
|
opts = { cmd = opts, hidden = true }
|
|
|
|
|
end
|
|
|
|
|
local num = vim.v.count > 0 and vim.v.count or 1
|
|
|
|
|
if not terms[opts.cmd] then
|
|
|
|
|
terms[opts.cmd] = {}
|
|
|
|
|
end
|
|
|
|
|
if not terms[opts.cmd][num] then
|
|
|
|
|
if not opts.count then
|
|
|
|
|
opts.count = vim.tbl_count(terms) * 100 + num
|
|
|
|
|
end
|
|
|
|
|
if not opts.on_exit then
|
|
|
|
|
opts.on_exit = function()
|
|
|
|
|
terms[opts.cmd][num] = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
terms[opts.cmd][num] = require("toggleterm.terminal").Terminal:new(opts)
|
|
|
|
|
end
|
|
|
|
|
terms[opts.cmd][num]:toggle()
|
2024-01-24 00:48:37 +01:00
|
|
|
|
end
|
2023-11-23 21:27:17 +01:00
|
|
|
|
|
2024-01-28 17:30:35 +01:00
|
|
|
|
function M.cmd(cmd, show_error)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
if type(cmd) == "string" then
|
|
|
|
|
cmd = { cmd }
|
|
|
|
|
end
|
|
|
|
|
local result = vim.fn.system(cmd)
|
|
|
|
|
local success = vim.api.nvim_get_vvar("shell_error") == 0
|
|
|
|
|
if not success and (show_error == nil or show_error) then
|
|
|
|
|
vim.api.nvim_err_writeln(
|
|
|
|
|
("Error running command %s\nError message:\n%s"):format(table.concat(cmd, " "), result)
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
return success and result:gsub("[\27\155][][()#;?%d]*[A-PRZcf-ntqry=><~]", "") or nil
|
2024-01-28 17:30:35 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-01-24 00:48:37 +01:00
|
|
|
|
function M.file_worktree(file, worktrees)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
worktrees = worktrees or vim.g.git_worktrees
|
|
|
|
|
file = file or vim.fn.expand("%")
|
|
|
|
|
for _, worktree in ipairs(worktrees) do
|
|
|
|
|
if
|
|
|
|
|
M.cmd({
|
|
|
|
|
"git",
|
|
|
|
|
"--work-tree",
|
|
|
|
|
worktree.toplevel,
|
|
|
|
|
"--git-dir",
|
|
|
|
|
worktree.gitdir,
|
|
|
|
|
"ls-files",
|
|
|
|
|
"--error-unmatch",
|
|
|
|
|
file,
|
|
|
|
|
}, false)
|
|
|
|
|
then
|
|
|
|
|
return worktree
|
|
|
|
|
end
|
|
|
|
|
end
|
2024-01-24 00:48:37 +01:00
|
|
|
|
end
|
2023-11-23 21:27:17 +01:00
|
|
|
|
|
2024-01-24 00:48:37 +01:00
|
|
|
|
function M.which_key_register()
|
2024-03-10 14:31:09 +01:00
|
|
|
|
if M.which_key_queue then
|
|
|
|
|
local wk_avail, wk = pcall(require, "which-key")
|
|
|
|
|
if wk_avail then
|
|
|
|
|
for mode, registration in pairs(M.which_key_queue) do
|
|
|
|
|
wk.register(registration, { mode = mode })
|
|
|
|
|
end
|
|
|
|
|
M.which_key_queue = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
2024-01-24 00:48:37 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-01-27 20:36:46 +01:00
|
|
|
|
function M.set_maps(map_table, base)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
base = base or {}
|
|
|
|
|
for mode, maps in pairs(map_table) do
|
|
|
|
|
for keymap, options in pairs(maps) do
|
|
|
|
|
if options then
|
|
|
|
|
local cmd = options
|
|
|
|
|
local keymap_opts = base
|
|
|
|
|
if type(options) == "table" then
|
|
|
|
|
cmd = options[1]
|
|
|
|
|
keymap_opts = vim.tbl_deep_extend("force", keymap_opts, options)
|
|
|
|
|
keymap_opts[1] = nil
|
|
|
|
|
end
|
|
|
|
|
if not cmd or keymap_opts.name then -- which-key mapping
|
|
|
|
|
if not keymap_opts.name then
|
|
|
|
|
keymap_opts.name = keymap_opts.desc
|
|
|
|
|
end
|
|
|
|
|
if not M.which_key_queue then
|
|
|
|
|
M.which_key_queue = {}
|
|
|
|
|
end
|
|
|
|
|
if not M.which_key_queue[mode] then
|
|
|
|
|
M.which_key_queue[mode] = {}
|
|
|
|
|
end
|
|
|
|
|
M.which_key_queue[mode][keymap] = keymap_opts
|
|
|
|
|
else -- not which-key mapping
|
|
|
|
|
vim.keymap.set(mode, keymap, cmd, keymap_opts)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if package.loaded["which-key"] then
|
|
|
|
|
M.which_key_register()
|
|
|
|
|
end
|
2024-01-25 00:10:11 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-03-10 16:47:43 +01:00
|
|
|
|
function M.del_buffer_autocmd(augroup, bufnr)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
local cmds_found, cmds = pcall(vim.api.nvim_get_autocmds, { group = augroup, buffer = bufnr })
|
|
|
|
|
if cmds_found then
|
|
|
|
|
vim.tbl_map(function(cmd)
|
|
|
|
|
vim.api.nvim_del_autocmd(cmd.id)
|
|
|
|
|
end, cmds)
|
|
|
|
|
end
|
2024-01-25 00:10:11 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-03-10 16:47:43 +01:00
|
|
|
|
function M.add_buffer_autocmd(augroup, bufnr, autocmds)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
if not vim.tbl_islist(autocmds) then
|
|
|
|
|
autocmds = { autocmds }
|
|
|
|
|
end
|
|
|
|
|
local cmds_found, cmds = pcall(vim.api.nvim_get_autocmds, { group = augroup, buffer = bufnr })
|
|
|
|
|
if not cmds_found or vim.tbl_isempty(cmds) then
|
|
|
|
|
vim.api.nvim_create_augroup(augroup, { clear = false })
|
|
|
|
|
for _, autocmd in ipairs(autocmds) do
|
|
|
|
|
local events = autocmd.events
|
|
|
|
|
autocmd.events = nil
|
|
|
|
|
autocmd.group = augroup
|
|
|
|
|
autocmd.buffer = bufnr
|
|
|
|
|
vim.api.nvim_create_autocmd(events, autocmd)
|
|
|
|
|
end
|
|
|
|
|
end
|
2024-01-25 00:10:11 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-03-10 16:47:43 +01:00
|
|
|
|
function M.has_capability(capability, filter)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
for _, client in ipairs(vim.lsp.get_active_clients(filter)) do
|
|
|
|
|
if client.supports_method(capability) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
2023-11-23 21:27:17 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-03-10 16:47:43 +01:00
|
|
|
|
function M.diagnostic_setup(conf)
|
|
|
|
|
for _, sign in ipairs(conf.signs) do
|
|
|
|
|
vim.fn.sign_define(sign.name, sign)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
end
|
2024-03-10 16:47:43 +01:00
|
|
|
|
vim.diagnostic.config(conf.diagnostic)
|
2024-01-25 00:10:11 +01:00
|
|
|
|
end
|
2024-01-24 10:53:48 +01:00
|
|
|
|
|
2024-01-28 15:04:25 +01:00
|
|
|
|
function M.has_value(table, value)
|
2024-03-10 14:31:09 +01:00
|
|
|
|
for _, v in ipairs(table) do
|
|
|
|
|
if v == value then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
2024-01-28 13:45:35 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-03-06 18:46:17 +01:00
|
|
|
|
function M.get_gwd(path)
|
2024-03-09 04:17:43 +01:00
|
|
|
|
return require("lspconfig.util").find_git_ancestor(path or vim.fn.getcwd())
|
2024-03-06 18:46:17 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function M.set_cwd()
|
2024-03-09 04:17:43 +01:00
|
|
|
|
local dir = M.get_gwd()
|
|
|
|
|
if dir ~= nil then
|
|
|
|
|
vim.fn.chdir(dir)
|
|
|
|
|
end
|
2024-03-06 18:46:17 +01:00
|
|
|
|
end
|
|
|
|
|
|
2024-03-10 23:00:57 +01:00
|
|
|
|
function M.get_lsp_key(key)
|
|
|
|
|
local ok, keys = pcall(require, "config.keys")
|
|
|
|
|
if ok then
|
|
|
|
|
return keys[key]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-03-12 08:48:32 +01:00
|
|
|
|
function M.lazy_file()
|
|
|
|
|
end
|
|
|
|
|
|
2023-11-23 21:27:17 +01:00
|
|
|
|
return M
|