summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2025-12-07 11:58:39 -0700
committerJosh Rahm <joshuarahm@gmail.com>2025-12-07 11:58:39 -0700
commit77e9fbb666006e52b4da6ac7db9130f892978ff7 (patch)
treed7a8836fd4347c4f9d9c61c75f2c933b8cca74d0
parent20239097d8906a3688201963466221ab044226b7 (diff)
downloadconfig.vim-77e9fbb666006e52b4da6ac7db9130f892978ff7.tar.gz
config.vim-77e9fbb666006e52b4da6ac7db9130f892978ff7.tar.bz2
config.vim-77e9fbb666006e52b4da6ac7db9130f892978ff7.zip
Remove smear cursor and update LSP configuration.HEADmain
-rw-r--r--init.vim2
-rw-r--r--lua/lsp.lua428
2 files changed, 235 insertions, 195 deletions
diff --git a/init.vim b/init.vim
index e2a597f..f6c3acf 100644
--- a/init.vim
+++ b/init.vim
@@ -49,7 +49,7 @@ Plug 'onsails/lspkind.nvim'
Plug 'kylechui/nvim-surround'
Plug 'vito-c/jq.vim'
Plug 'EdenEast/nightfox.nvim'
-Plug 'sphamba/smear-cursor.nvim'
+" Plug 'sphamba/smear-cursor.nvim'
Plug 'smoka7/hop.nvim'
Plug 'lewis6991/gitsigns.nvim'
diff --git a/lua/lsp.lua b/lua/lsp.lua
index 9a34981..29b4368 100644
--- a/lua/lsp.lua
+++ b/lua/lsp.lua
@@ -1,60 +1,15 @@
-local vim = assert(vim)
+-- my_lsp.lua
+local ok_cmp, cmp = pcall(require, "cmp")
+local ok_kind, lspkind = pcall(require, "lspkind")
+local ok_cmp_caps, cmp_caps = pcall(require, "cmp_nvim_lsp")
+local has_lspconfig, lspconfig = pcall(require, "lspconfig")
-local nvim_lsp = require("lspconfig")
-
-nvim_lsp.bashls.setup {}
-nvim_lsp.clangd.setup {
- filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' },
-}
-nvim_lsp.jqls.setup {}
-nvim_lsp.lua_ls.setup {}
-nvim_lsp.ocamllsp.setup {}
-nvim_lsp.perlpls.setup {}
-nvim_lsp.rust_analyzer.setup {}
-nvim_lsp.verible.setup {}
-nvim_lsp.vimls.setup {}
-nvim_lsp.zls.setup {}
-nvim_lsp.texlab.setup {}
-nvim_lsp.hls.setup {
- settings = {
- haskell = {
- plugin = {
- semanticTokens = {
- globalOn = true
- }
- }
- }
- }
-}
-nvim_lsp.pylsp.setup {
- settings = {
- pylsp = {
- plugins = {
- pycodestyle = {
- enabled = false
- }
- }
- }
- }
-}
-
-local has_words_before = function()
- unpack = unpack or table.unpack
- local line, col = unpack(vim.api.nvim_win_get_cursor(0))
- return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
-end
-
-local feedkey = function(key, mode)
- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true)
-end
-
--- 2. Configure CMP
+-- ── completion (cmp) ───────────────────────────────────────────────────────────
vim.opt.completeopt = { "menu", "menuone", "noselect" }
-
--- Don't show matching
vim.opt.shortmess:append("c")
-local lspkind = require("lspkind") lspkind.init({
+if ok_kind then
+ lspkind.init({
symbol_map = {
Text = "󰉿",
Method = "󰊕",
@@ -82,170 +37,255 @@ local lspkind = require("lspkind") lspkind.init({
Operator = "󰆕",
TypeParameter = "τ",
},
-})
-
-local cmp = require("cmp")
-
-cmp.setup({
- mapping = {
- ["<C-d>"] = cmp.mapping.scroll_docs(-4, { "i", "s" }),
- ["<C-u>"] = cmp.mapping.scroll_docs(4, { "i", "s" }),
- ["<C-e>"] = cmp.mapping.close(),
- ["<C-Space>"] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }),
- ["<C-n>"] = cmp.mapping(function(fallback)
- cmp.select_next_item()
- -- Kill any outstanding snippets
- vim.fn["vsnip#deactivate"]()
- end, { "i", "s" }),
- ["<C-p>"] = cmp.mapping(function(fallback)
- cmp.select_prev_item()
- -- Kill any outstanding snippets
- vim.fn["vsnip#deactivate"]()
- end, { "i", "s" }),
-
- ["<Tab>"] = cmp.mapping(function(fallback)
- if vim.fn["vsnip#available"](1) == 1 then
- feedkey("<Plug>(vsnip-expand-or-jump)", "")
- elseif cmp.visible() then
- cmp.mapping.confirm({ select = true })()
- elseif has_words_before() then
- cmp.complete()
- else
- fallback() -- The fallback function sends a already mapped key. In this case, it's probably `<Tab>`.
- end
- end, { "i", "s" }),
-
- ["<S-Tab>"] = cmp.mapping(function()
- if cmp.visible() then
- cmp.select_prev_item()
- elseif vim.fn["vsnip#jumpable"](-1) == 1 then
- feedkey("<Plug>(vsnip-jump-prev)", "")
- end
- end, { "i", "s" }),
- },
+ })
+end
- formatting = {
- format = lspkind.cmp_format({
- mode = 'symbol_text',
- maxwidth = 50,
- ellipsis_char = '...',
- show_labelDetails = true,
- before = function(_, vim_item)
- local function split_silly_function_arguments(str)
- if string.len(str) == 0 or string.find(str, "[(]") == nil then
- return str, ""
- end
+local function has_words_before()
+ local unpack = unpack or table.unpack
+ local line, col = unpack(vim.api.nvim_win_get_cursor(0))
+ if col == 0 then return false end
+ local l = vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1] or ""
+ return l:sub(col, col):match("%s") == nil
+end
- local name_start, name_end = 1, string.find(str, "[(]") - 1
- local function_name = string.sub(str, name_start, name_end)
- local arguments = string.sub(str, name_end + 1)
+local function feedkey(key, mode)
+ vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true)
+end
- return function_name, arguments
+if ok_cmp then
+ cmp.setup({
+ mapping = {
+ ["<C-d>"] = cmp.mapping.scroll_docs(-4, { "i", "s" }),
+ ["<C-u>"] = cmp.mapping.scroll_docs(4, { "i", "s" }),
+ ["<C-e>"] = cmp.mapping.close(),
+ ["<C-Space>"] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }),
+ ["<C-n>"] = cmp.mapping(function()
+ cmp.select_next_item()
+ pcall(vim.fn["vsnip#deactivate"])
+ end, { "i", "s" }),
+ ["<C-p>"] = cmp.mapping(function()
+ cmp.select_prev_item()
+ pcall(vim.fn["vsnip#deactivate"])
+ end, { "i", "s" }),
+ ["<Tab>"] = cmp.mapping(function(fallback)
+ if vim.fn == 1 then
+ feedkey("<Plug>(vsnip-expand-or-jump)", "")
+ elseif cmp.visible() then
+ cmp.mapping.confirm({ select = true })()
+ elseif has_words_before() then
+ cmp.complete()
+ else
+ fallback()
end
-
- local verbosity = 1
- local over_9000 = 2
- if vim.bo.filetype == 'java' then
- verbosity = over_9000
- if vim_item.kind == "Method" then
- local name, args = split_silly_function_arguments(vim_item.abbr)
- vim_item.abbr = name
- vim_item.menu = args .. (vim_item.menu or "")
- end
+ end, { "i", "s" }),
+ ["<S-Tab>"] = cmp.mapping(function()
+ if cmp.visible() then
+ cmp.select_prev_item()
+ elseif vim.fn["vsnip#jumpable"](-1) == 1 then
+ feedkey("<Plug>(vsnip-jump-prev)", "")
end
- vim_item.abbr = string.sub(vim_item.abbr, 1, 20 * verbosity)
- vim_item.menu = string.sub(vim_item.menu or "", 1, 20 * verbosity)
- return vim_item
- end
- })
- },
-
- sources = {
- { name = "nvim_lsp" },
- { name = "path" },
- { name = "vim_vsnip" },
- { name = "buffer", keyword_length = 5 },
- },
-
- sorting = {
- comparators = {}, -- We stop all sorting to let the lsp do the sorting
- },
+ end, { "i", "s" }),
+ },
+ formatting = ok_kind and {
+ format = lspkind.cmp_format({
+ mode = "symbol_text",
+ maxwidth = 50,
+ ellipsis_char = "...",
+ show_labelDetails = true,
+ before = function(_, item)
+ local function split_args(s)
+ if #s == 0 or not s:find("%(") then return s, "" end
+ local i = s:find("%(") - 1
+ return s:sub(1, i), s:sub(i + 1)
+ end
+ local verbosity = (vim.bo.filetype == "java") and 2 or 1
+ if vim.bo.filetype == "java" and item.kind == "Method" then
+ local name, args = split_args(item.abbr)
+ item.abbr = name
+ item.menu = (args or "") .. (item.menu or "")
+ end
+ item.abbr = item.abbr:sub(1, 20 * verbosity)
+ item.menu = (item.menu or ""):sub(1, 20 * verbosity)
+ return item
+ end,
+ }),
+ } or nil,
+ sources = {
+ { name = "nvim_lsp" },
+ { name = "path" },
+ { name = "vim_vsnip" },
+ { name = "buffer", keyword_length = 5 },
+ },
+ sorting = { comparators = {} }, -- let LSP decide
+ snippet = {
+ expand = function(args) vim.fn["vsnip#anonymous"](args.body) end,
+ },
+ experimental = { native_menu = false, ghost_text = true },
+ })
- snippet = {
- expand = function(args)
- vim.fn["vsnip#anonymous"](args.body)
+ -- zsh source on zsh buffers
+ vim.api.nvim_create_augroup("CmpZsh", { clear = true })
+ vim.api.nvim_create_autocmd("FileType", {
+ group = "CmpZsh",
+ pattern = "zsh",
+ callback = function()
+ require("cmp").setup.buffer { sources = { { name = "zsh" } } }
end,
- },
-
- experimental = {
- native_menu = false,
- ghost_text = true,
- },
-})
-
-vim.cmd([[
- augroup CmpZsh
- au!
- autocmd Filetype zsh lua require'cmp'.setup.buffer { sources = { { name = "zsh" }, } }
- augroup END
-]])
+ })
+end
+-- ── LSP shared on_attach & capabilities ───────────────────────────────────────
local M = {}
--- 3. Set up CiderLSP
+
M.on_attach = function(client, bufnr)
- vim.api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.vim.lsp.omnifunc")
- if vim.lsp.formatexpr then -- Neovim v0.6.0+ only.
- vim.api.nvim_buf_set_option(bufnr, "formatexpr", "v:lua.vim.lsp.formatexpr")
- end
- if vim.lsp.tagfunc then
- vim.api.nvim_buf_set_option(bufnr, "tagfunc", "v:lua.vim.lsp.tagfunc")
+ -- omnifunc, tagfunc, formatexpr
+ vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc"
+ if vim.lsp.formatexpr then vim.bo[bufnr].formatexpr = "v:lua.vim.lsp.formatexpr" end
+ if vim.lsp.tagfunc then vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc" end
+
+ local map = function(mode, lhs, rhs)
+ vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, noremap = true })
end
+ map("n", "<leader>rn", vim.lsp.buf.rename)
+ map("n", "<leader>ca", vim.lsp.buf.code_action)
+ map("n", "<M-k>", vim.lsp.buf.hover)
+ map("n", "g0", vim.lsp.buf.document_symbol)
+ map("n", "gW", vim.lsp.buf.workspace_symbol)
+ map("n", "gd", vim.lsp.buf.definition)
+ map("n", "gD", vim.lsp.buf.declaration)
+ map("n", "gi", vim.lsp.buf.implementation)
+ map("n", "gr", vim.lsp.buf.references)
+ map("n", "<C-k>", vim.lsp.buf.signature_help)
+ map("n", "g<space>", vim.lsp.buf.type_definition)
+ map("n", "[d", vim.diagnostic.goto_prev)
+ map("n", "]d", vim.diagnostic.goto_next)
- local opts = { noremap = true, silent = true }
- vim.api.nvim_buf_set_keymap(bufnr, "n", "<leader>rn", "<cmd>lua vim.lsp.buf.rename()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "<leader>ca", "<cmd>lua vim.lsp.buf.code_action()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "<M-k>", "<cmd>lua vim.lsp.buf.hover()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "g0", "<cmd>lua vim.lsp.buf.document_symbol()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "gW", "<cmd>lua vim.lsp.buf.workspace_symbol()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "<cmd>lua vim.lsp.buf.definition()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "<cmd>lua vim.lsp.buf.declaration()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "<cmd>lua vim.lsp.buf.implementation()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "<cmd>lua vim.lsp.buf.references()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "<C-k>", "<cmd>lua vim.lsp.buf.signature_help()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "g<space>", "<cmd>lua vim.lsp.buf.type_definition()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", "<cmd>lua vim.diagnostic.goto_prev()<CR>", opts)
- vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", "<cmd>lua vim.diagnostic.goto_next()<CR>", opts)
-
- vim.api.nvim_command("augroup LSP")
- vim.api.nvim_command("autocmd!")
+ -- document highlight (only if server supports it)
if client.server_capabilities.documentHighlightProvider then
- vim.api.nvim_create_autocmd("CursorHold", {
- buffer = bufnr,
- callback = vim.lsp.buf.document_highlight
- })
- vim.api.nvim_create_autocmd("CursorHoldI", {
- buffer = bufnr,
- callback = vim.lsp.buf.document_highlight
+ local gid = vim.api.nvim_create_augroup("LspDocumentHighlight" .. bufnr, { clear = true })
+ vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
+ group = gid, buffer = bufnr, callback = vim.lsp.buf.document_highlight,
})
vim.api.nvim_create_autocmd("CursorMoved", {
- buffer = bufnr,
- callback = vim.lsp.buf.buf_clear_references
+ group = gid, buffer = bufnr, callback = vim.lsp.buf.clear_references,
})
end
- vim.api.nvim_command("augroup END")
- -- When an LSP is attached, we should just set the sign column to yes in order
- -- to avoid the jarring behavior of it appearing and disappearing rapidly.
- vim.opt_local.signcolumn = 'yes'
+ vim.opt_local.signcolumn = "yes"
end
-vim.cmd[[hi DiagnosticUnderlineError gui=undercurl guisp=salmon]]
-vim.cmd[[hi DiagnosticUnderlineWarn gui=undercurl guisp=gold]]
+local capabilities = vim.lsp.protocol.make_client_capabilities()
+if ok_cmp_caps then
+ capabilities = cmp_caps.default_capabilities(capabilities)
+end
-local signs = { Error = " ", Warn = " ", Hint = " ", Info = " " }
-for type, icon in pairs(signs) do
+-- nice diagnostics styling
+vim.cmd [[hi DiagnosticUnderlineError gui=undercurl guisp=salmon]]
+vim.cmd [[hi DiagnosticUnderlineWarn gui=undercurl guisp=gold]]
+for type, icon in pairs({ Error = " ", Warn = " ", Hint = " ", Info = " " }) do
local hl = "DiagnosticSign" .. type
vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = "" })
end
+-- ── Servers (one table to rule them all) ──────────────────────────────────────
+local servers = {
+ bashls = { filetypes = { "bash", "sh" } },
+ clangd = { filetypes = { "c", "cpp", "objc", "objcpp", "cuda" } },
+ jqls = { filetypes = { "jq" } },
+ lua_ls = { filetypes = { "lua" } },
+ ocamllsp = {},
+ perlpls = {},
+ rust_analyzer = {
+ settings = {
+ semantic_tokens = {
+ modifiers = {
+ disabled = { "dead" },
+ },
+ },
+ }
+ },
+ verible = {},
+ vimls = {},
+ zls = {},
+ texlab = {},
+ hls = {
+ settings = { haskell = { plugin = { semanticTokens = { globalOn = true } } } }
+ },
+ pylsp = {
+ settings = { pylsp = { plugins = { pycodestyle = { enabled = false } } } }
+ },
+}
+
+-- Fallback command guesses for native start (used only if lspconfig is absent)
+local default_cmd = {
+ bashls = { "bash-language-server", "start" },
+ clangd = { "clangd" },
+ jqls = { "jq-lsp" },
+ lua_ls = { "lua-language-server" },
+ ocamllsp = { "ocamllsp" },
+ perlpls = { "perlpls" },
+ rust_analyzer = { "rust-analyzer" },
+ verible = { "verible-verilog-ls" },
+ vimls = { "vim-language-server", "--stdio" },
+ zls = { "zls" },
+ texlab = { "texlab" },
+ hls = { "haskell-language-server-wrapper", "--lsp" },
+ pylsp = { "pylsp" },
+}
+
+-- ── Setup: prefer native vim.lsp.config, fallback to lspconfig ───────────────
+local has_native = (vim.lsp and vim.lsp.config and vim.lsp.start)
+
+local function setup_with_native(name, opts)
+ -- Build a vim.lsp.config() object and start per-filetype
+ local cfg = vim.lsp.config(name, {
+ name = name,
+ cmd = opts.cmd or default_cmd[name],
+ root_dir = opts.root_dir, -- optional; can rely on server defaults
+ filetypes = opts.filetypes,
+ settings = opts.settings,
+ capabilities = capabilities,
+ on_attach = M.on_attach,
+ })
+
+ vim.lsp.enable(name);
+
+ -- if cfg.cmd == nil then
+ -- vim.notify(("LSP %s: no cmd found; skipping native start."):format(name), vim.log.levels.WARN)
+ -- return
+ -- end
+
+ -- Start when a matching buffer opens
+ -- local pat = opts.filetypes or "*"
+ -- vim.api.nvim_create_autocmd("FileType", {
+ -- pattern = pat,
+ -- callback = function(args)
+ -- -- Only start if ft matches the server's filetypes (or none specified)
+ -- if not cfg.filetypes or vim.tbl_contains(cfg.filetypes, vim.bo[args.buf].filetype) then
+ -- vim.lsp.start(cfg, { bufnr = args.buf })
+ -- end
+ -- end,
+ -- })
+end
+
+local function setup_with_lspconfig(name, opts)
+ if not has_lspconfig then
+ vim.notify(("lspconfig not found; cannot setup %s"):format(name), vim.log.levels.WARN)
+ return
+ end
+ local final = vim.tbl_deep_extend("force", {
+ capabilities = capabilities,
+ on_attach = M.on_attach,
+ }, opts or {})
+ lspconfig[name].setup(final)
+end
+
+for name, opts in pairs(servers) do
+ if has_native then
+ setup_with_native(name, opts)
+ else
+ setup_with_lspconfig(name, opts)
+ end
+end
+
return M