aboutsummaryrefslogtreecommitdiff
path: root/common/nvim/lua/plugins/lsp.lua
diff options
context:
space:
mode:
Diffstat (limited to 'common/nvim/lua/plugins/lsp.lua')
-rwxr-xr-xcommon/nvim/lua/plugins/lsp.lua674
1 files changed, 0 insertions, 674 deletions
diff --git a/common/nvim/lua/plugins/lsp.lua b/common/nvim/lua/plugins/lsp.lua
deleted file mode 100755
index 5ed1152..0000000
--- a/common/nvim/lua/plugins/lsp.lua
+++ /dev/null
@@ -1,674 +0,0 @@
-local M = {}
-
--- Safe require helper
-local function safe_require(name)
- local ok, mod = pcall(require, name)
- return ok and mod or nil
-end
-
--- Autocmd groups for managing event listeners
-local augroup_format = vim.api.nvim_create_augroup("LspFormattingOnSave", { clear = true })
-local augroup_diag_float = vim.api.nvim_create_augroup("ShowLineDiagnostics", { clear = true })
-local augroup_diag_load = vim.api.nvim_create_augroup("OpenDiagnosticsOnLoad", { clear = true })
-local augroup_highlight = vim.api.nvim_create_augroup("LspDocumentHighlight", { clear = true })
-
--- Border for floating windows
-local border = {
- { "┌", "FloatBorder" }, { "─", "FloatBorder" }, { "┐", "FloatBorder" },
- { "│", "FloatBorder" }, { "┘", "FloatBorder" }, { "─", "FloatBorder" },
- { "└", "FloatBorder" }, { "│", "FloatBorder" }
-}
-
--- Initialize LSP modules
-local function init_modules()
- -- Silently try to load each module
- M.lspconfig = safe_require("lspconfig")
- M.mason = safe_require("mason")
- M.mason_lspconfig = safe_require("mason-lspconfig")
- M.mason_tool_installer = safe_require("mason-tool-installer")
- M.null_ls = safe_require("null-ls")
-
- if M.null_ls then
- M.builtins = M.null_ls.builtins
- end
-
- return true
-end
-
--- Check Neovim version compatibility and feature availability
-local function has_feature(feature)
- if feature == "diagnostic_api" then
- return vim.fn.has("nvim-0.6") == 1
- elseif feature == "native_lsp_config" then
- -- Check for both vim.lsp.enable AND vim.lsp.config
- return vim.fn.has("nvim-0.11") == 1 and vim.lsp.enable ~= nil
- elseif feature == "lsp_get_client_by_id" then
- return vim.fn.has("nvim-0.10") == 1
- elseif feature == "cmp_nvim_lsp" then
- return pcall(require, "cmp_nvim_lsp")
- elseif feature == "virtual_text_disabled_by_default" then
- return vim.fn.has("nvim-0.11") == 1
- elseif feature == "deprecated_lsp_handlers" then
- -- vim.lsp.handlers.hover and signature_help deprecated in 0.12, removed in 0.13
- return vim.fn.has("nvim-0.12") == 0
- elseif feature == "new_lsp_config_api" then
- -- New LSP config API available from 0.12+
- return vim.fn.has("nvim-0.12") == 1 and vim.lsp.config ~= nil
- end
- return false
-end
-
--- Backwards compatible capabilities setup
-local function setup_capabilities()
- local capabilities
-
- if has_feature("cmp_nvim_lsp") then
- capabilities = require('cmp_nvim_lsp').default_capabilities()
- elseif vim.lsp.protocol and vim.lsp.protocol.make_client_capabilities then
- capabilities = vim.lsp.protocol.make_client_capabilities()
- else
- capabilities = {}
- end
-
- -- Add snippet support if available
- if capabilities.textDocument then
- capabilities.textDocument.completion = capabilities.textDocument.completion or {}
- capabilities.textDocument.completion.completionItem =
- capabilities.textDocument.completion.completionItem or {}
- capabilities.textDocument.completion.completionItem.snippetSupport = true
- end
-
- -- Set offset encoding for newer versions (0.11+ supports utf-8 and utf-32)
- if vim.fn.has("nvim-0.11") == 1 then
- capabilities.offsetEncoding = { "utf-8", "utf-32", "utf-16" }
- elseif vim.fn.has("nvim-0.9") == 1 then
- capabilities.offsetEncoding = { "utf-8", "utf-16" }
- end
-
- return capabilities
-end
-
--- Default LSP keymaps (fallback if external not available)
-local function setup_fallback_keymaps(bufnr)
- -- Only set up minimal fallbacks, prefer external setup
- local opts = { buffer = bufnr, silent = true, noremap = true }
- vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
- vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
- vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts)
- vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
-end
-
--- Create LSP directory and config files for native LSP
-local function setup_native_lsp_configs()
- local config_path = vim.fn.stdpath("config")
- local lsp_dir = config_path .. "/lsp"
-
- -- Create lsp directory if it doesn't exist
- vim.fn.mkdir(lsp_dir, "p")
-
- -- LSP server configurations for native config
- local server_configs = {
- lua_ls = {
- cmd = { "lua-language-server" },
- filetypes = { "lua" },
- root_markers = { ".luarc.json", ".luarc.jsonc", ".luacheckrc", ".stylua.toml", "stylua.toml", "selene.toml", "selene.yml" },
- settings = {
- Lua = {
- diagnostics = {
- globals = { "vim", "use", "_G", "packer_plugins", "P" },
- disable = {
- "undefined-global",
- "lowercase-global",
- "unused-local",
- "unused-vararg",
- "trailing-space"
- },
- },
- workspace = {
- library = {
- vim.env.VIMRUNTIME,
- "${3rd}/luv/library",
- "${3rd}/busted/library",
- },
- checkThirdParty = false,
- },
- telemetry = {
- enable = false,
- },
- },
- },
- },
-
- pyright = {
- cmd = { "pyright-langserver", "--stdio" },
- filetypes = { "python" },
- root_markers = { "pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "pyrightconfig.json" },
- settings = {
- python = {
- formatting = {
- provider = "none"
- }
- }
- }
- },
-
- ts_ls = {
- cmd = { "typescript-language-server", "--stdio" },
- filetypes = { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" },
- root_markers = { "tsconfig.json", "jsconfig.json", "package.json" },
- init_options = {
- disableAutomaticTypeAcquisition = true
- },
- },
-
- rust_analyzer = {
- cmd = { "rust-analyzer" },
- filetypes = { "rust" },
- root_markers = { "Cargo.toml", "rust-project.json" },
- },
-
- clangd = {
- cmd = { "clangd", "--background-index", "--clang-tidy", "--header-insertion=iwyu" },
- filetypes = { "c", "cpp", "objc", "objcpp", "cuda", "proto" },
- root_markers = { ".clangd", ".clang-tidy", ".clang-format", "compile_commands.json", "compile_flags.txt", "configure.ac" },
- },
-
- gopls = {
- cmd = { "gopls" },
- filetypes = { "go", "gomod", "gowork", "gotmpl" },
- root_markers = { "go.work", "go.mod" },
- settings = {
- gopls = {
- gofumpt = true,
- codelenses = {
- gc_details = false,
- generate = true,
- regenerate_cgo = true,
- run_govulncheck = true,
- test = true,
- tidy = true,
- upgrade_dependency = true,
- vendor = true,
- },
- hints = {
- assignVariableTypes = true,
- compositeLiteralFields = true,
- compositeLiteralTypes = true,
- constantValues = true,
- functionTypeParameters = true,
- parameterNames = true,
- rangeVariableTypes = true,
- },
- analyses = {
- fieldalignment = true,
- nilness = true,
- unusedparams = true,
- unusedwrite = true,
- useany = true,
- },
- usePlaceholders = true,
- completeUnimported = true,
- staticcheck = true,
- directoryFilters = { "-.git", "-.vscode", "-.idea", "-.vscode-test", "-node_modules" },
- semanticTokens = true,
- },
- },
- },
-
- -- Add more basic configs
- bashls = {
- cmd = { "bash-language-server", "start" },
- filetypes = { "sh", "bash" },
- },
-
- --html = {
- -- cmd = { "vscode-html-language-server", "--stdio" },
- -- filetypes = { "html" },
- --},
-
- --cssls = {
- -- cmd = { "vscode-css-language-server", "--stdio" },
- -- filetypes = { "css", "scss", "less" },
- --},
-
- --jsonls = {
- -- cmd = { "vscode-json-language-server", "--stdio" },
- -- filetypes = { "json", "jsonc" },
- --},
-
- yamlls = {
- cmd = { "yaml-language-server", "--stdio" },
- filetypes = { "yaml", "yml" },
- },
- }
-
- -- Write config files to lsp directory
- for server_name, config in pairs(server_configs) do
- local file_path = lsp_dir .. "/" .. server_name .. ".lua"
- local file_content = "return " .. vim.inspect(config)
-
- -- Only write if file doesn't exist to avoid overwriting user customizations
- if vim.fn.filereadable(file_path) == 0 then
- local file = io.open(file_path, "w")
- if file then
- file:write(file_content)
- file:close()
- vim.notify("Created LSP config: " .. file_path, vim.log.levels.DEBUG)
- end
- end
- end
-
- return vim.tbl_keys(server_configs)
-end
-
--- Set up LSP on_attach function
-local function create_on_attach()
- return function(client, bufnr)
- -- Your existing keymap setup function from keys.lua
- if _G.setup_lsp_keymaps then
- _G.setup_lsp_keymaps(bufnr)
- else
- setup_fallback_keymaps(bufnr)
- end
-
- -- Disable LSP formatting in favor of null-ls (if null-ls is available)
- if M.null_ls then
- client.server_capabilities.documentFormattingProvider = false
- client.server_capabilities.documentRangeFormattingProvider = false
- end
-
- -- Disable specific LSP capabilities to avoid conflicts
- if client.name == "ruff" then
- -- Disable ruff hover in favor of Pyright
- client.server_capabilities.hoverProvider = false
- elseif client.name == "ts_ls" then
- -- Disable ts_ls formatting in favor of prettier via null-ls
- client.server_capabilities.documentFormattingProvider = false
- client.server_capabilities.documentRangeFormattingProvider = false
- elseif client.name == "pyright" and M.null_ls then
- -- Disable pyright formatting in favor of black/isort via null-ls
- client.server_capabilities.documentFormattingProvider = false
- client.server_capabilities.documentRangeFormattingProvider = false
- end
-
- -- Set log level (backwards compatible)
- if vim.lsp.set_log_level then
- vim.lsp.set_log_level("warn")
- end
-
- -- Document highlight on cursor hold
- if client.server_capabilities and client.server_capabilities.documentHighlightProvider then
- vim.api.nvim_create_autocmd("CursorHold", {
- group = augroup_highlight,
- buffer = bufnr,
- callback = function()
- if vim.lsp.buf.document_highlight then
- vim.lsp.buf.document_highlight()
- end
- end,
- })
- vim.api.nvim_create_autocmd("CursorMoved", {
- group = augroup_highlight,
- buffer = bufnr,
- callback = function()
- if vim.lsp.buf.clear_references then
- vim.lsp.buf.clear_references()
- end
- end,
- })
- end
- end
-end
-
--- Set up basic LSP configuration
-function M.setup()
- -- Initialize all required modules
- init_modules()
-
- -- Enable virtual_text diagnostics by default for 0.11+ (since it's disabled by default)
- if has_feature("virtual_text_disabled_by_default") then
- vim.diagnostic.config({ virtual_text = true })
- end
-
- -- Set up Mason if available (useful for tool management)
- if M.mason then
- M.mason.setup({
- ui = {
- border = 'rounded',
- icons = {
- package_installed = '✓',
- package_pending = '➜',
- package_uninstalled = '✗'
- }
- }
- })
- end
-
- -- Set up mason-tool-installer if available
- if M.mason_tool_installer then
- M.mason_tool_installer.setup({
- ensure_installed = {
- -- Language servers
- "lua-language-server", "pyright", "typescript-language-server", "rust-analyzer",
- "clangd", "bash-language-server", "yaml-language-server",
- -- Formatters
- "stylua", "clang-format", "prettier", "shfmt", "black", "isort", "goimports",
- "sql-formatter", "shellharden",
- -- Linters/Diagnostics
- "eslint_d", "selene", "flake8", "dotenv-linter", "phpcs",
- -- Utilities
- "jq"
- },
- auto_update = false,
- run_on_start = true,
- start_delay = 3000,
- })
- end
-
- -- Set up null-ls if available
- if M.null_ls and M.builtins then
- local sources = {
- M.builtins.diagnostics.selene.with({
- condition = function(utils)
- return utils.root_has_file({"selene.toml"})
- end,
- }),
- M.builtins.diagnostics.dotenv_linter,
- M.builtins.diagnostics.tidy,
- M.builtins.diagnostics.phpcs.with({
- condition = function(utils)
- return utils.root_has_file({"phpcs.xml", "phpcs.xml.dist", ".phpcs.xml", ".phpcs.xml.dist"})
- end,
- }),
-
- -- Formatters (prioritized over LSP formatting)
- M.builtins.formatting.stylua.with({
- extra_args = { "--quote-style", "AutoPreferSingle", "--indent-width", "2", "--column-width", "160" },
- condition = function(utils)
- return utils.root_has_file({"stylua.toml", ".stylua.toml"})
- end,
- }),
- M.builtins.formatting.prettier.with({
- extra_args = { "--single-quote", "--tab-width", "4", "--print-width", "100" },
- filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact", "vue", "css", "scss", "less", "html", "json", "jsonc", "yaml", "markdown", "graphql", "handlebars" },
- prefer_local = "node_modules/.bin",
- }),
- M.builtins.formatting.black.with({
- extra_args = { "--fast" },
- prefer_local = ".venv/bin",
- }),
- M.builtins.formatting.isort.with({
- extra_args = { "--profile", "black" },
- prefer_local = ".venv/bin",
- }),
- M.builtins.formatting.goimports,
- M.builtins.formatting.clang_format.with({
- extra_args = { "--style", "{BasedOnStyle: Google, IndentWidth: 4}" }
- }),
- M.builtins.formatting.shfmt.with({
- extra_args = { "-i", "2", "-ci" }
- }),
- M.builtins.formatting.shellharden,
- M.builtins.formatting.sql_formatter,
- M.builtins.formatting.dart_format,
-
- -- Code actions
- M.builtins.code_actions.gitsigns,
- M.builtins.code_actions.gitrebase,
- }
-
- M.null_ls.setup({
- sources = sources,
- update_in_insert = false,
- on_attach = function(client, bufnr)
- -- Disable LSP formatting in favor of null-ls
- client.server_capabilities.documentFormattingProvider = false
- client.server_capabilities.documentRangeFormattingProvider = false
-
- local function lsp_supports_method(client, method)
- if client.supports_method then
- return client:supports_method(method)
- elseif client.server_capabilities then
- local capability_map = {
- ["textDocument/formatting"] = "documentFormattingProvider",
- ["textDocument/rangeFormatting"] = "documentRangeFormattingProvider",
- ["textDocument/hover"] = "hoverProvider",
- ["textDocument/signatureHelp"] = "signatureHelpProvider",
- ["textDocument/documentHighlight"] = "documentHighlightProvider",
- }
- local cap = capability_map[method]
- return cap and client.server_capabilities[cap]
- end
- return false
- end
-
- if lsp_supports_method(client, "textDocument/formatting") then
- vim.api.nvim_create_autocmd("BufWritePre", {
- group = augroup_format,
- buffer = bufnr,
- callback = function()
- if vim.fn.has("nvim-0.8") == 1 then
- vim.lsp.buf.format({
- async = false,
- bufnr = bufnr,
- filter = function(formatting_client)
- return formatting_client.name == "null-ls"
- end,
- })
- else
- vim.lsp.buf.formatting_sync()
- end
- end,
- })
- end
- end,
- })
- end
-
- -- Set up LSP capabilities
- local capabilities = setup_capabilities()
- local on_attach = create_on_attach()
-
- -- Set up LSP handlers with version compatibility (avoid deprecated APIs)
- if has_feature("deprecated_lsp_handlers") then
- -- Use old handler setup for versions before 0.12
- if vim.lsp.handlers then
- vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(
- vim.lsp.handlers.hover, { border = 'rounded' }
- )
-
- vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with(
- vim.lsp.handlers.signature_help, { border = 'rounded' }
- )
- end
- else
- -- Use new handler setup for 0.12+ (when old handlers are deprecated/removed)
- if vim.lsp.handlers then
- vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(
- vim.lsp.handlers['textDocument/hover'], { border = 'rounded' }
- )
-
- vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with(
- vim.lsp.handlers['textDocument/signatureHelp'], { border = 'rounded' }
- )
- end
- end
-
- -- Choose configuration method based on Neovim version and available features
- if has_feature("native_lsp_config") then
- -- Set up native LSP configuration
- local servers = setup_native_lsp_configs()
-
- -- Set default on_attach and capabilities for all LSP servers
- vim.lsp.config('*', {
- on_attach = on_attach,
- capabilities = capabilities,
- })
-
- -- Enable the LSP servers
- vim.lsp.enable(servers)
-
- elseif M.mason_lspconfig and M.lspconfig then
- -- Set up mason-lspconfig if available
- if M.mason_lspconfig then
- M.mason_lspconfig.setup({
- ensure_installed = {
- "lua_ls", "pyright", "ts_ls", "rust_analyzer", "clangd", "gopls",
- "bashls", "html", "cssls", "jsonls", "yamlls"
- },
- automatic_installation = true,
- })
- end
-
- -- Use traditional lspconfig with mason
- local enabled_servers = {}
-
- local server_configs = {
- lua_ls = {
- settings = {
- Lua = {
- diagnostics = {
- globals = { "vim", "use", "_G", "packer_plugins", "P" },
- },
- workspace = {
- library = {
- vim.env.VIMRUNTIME,
- "${3rd}/luv/library",
- "${3rd}/busted/library",
- },
- checkThirdParty = false,
- },
- telemetry = { enable = false },
- },
- },
- },
- pyright = {
- settings = {
- python = {
- formatting = { provider = "none" }
- }
- }
- },
- ts_ls = {
- init_options = {
- disableAutomaticTypeAcquisition = true
- },
- },
- clangd = {
- cmd = { "clangd", "--background-index", "--clang-tidy", "--header-insertion=iwyu" },
- },
- gopls = {
- settings = {
- gopls = {
- gofumpt = true,
- usePlaceholders = true,
- completeUnimported = true,
- staticcheck = true,
- },
- },
- },
- }
-
- M.mason_lspconfig.setup_handlers({
- function(server_name)
- if not enabled_servers[server_name] then
- local config = server_configs[server_name] or {}
- config.on_attach = on_attach
- config.capabilities = capabilities
- M.lspconfig[server_name].setup(config)
- enabled_servers[server_name] = true
- end
- end,
- })
-
- elseif M.lspconfig then
- -- Fallback: Set up servers manually if mason-lspconfig is not available
- local servers = { 'lua_ls', 'pyright', 'ts_ls', 'rust_analyzer', 'clangd', 'gopls', 'bashls', 'html', 'cssls', 'jsonls', 'yamlls' }
- local enabled_servers = {}
-
- for _, server in ipairs(servers) do
- if not enabled_servers[server] and M.lspconfig[server] then
- local config = {
- on_attach = on_attach,
- capabilities = capabilities,
- }
- M.lspconfig[server].setup(config)
- enabled_servers[server] = true
- end
- end
- end
-
- return true
-end
-
--- Global toggle for diagnostics (backwards compatible)
-vim.g.diagnostics_visible = true
-function _G.toggle_diagnostics()
- if has_feature("diagnostic_api") then
- if vim.g.diagnostics_visible then
- vim.g.diagnostics_visible = false
- vim.diagnostic.disable()
- else
- vim.g.diagnostics_visible = true
- vim.diagnostic.enable()
- end
- else
- -- Fallback for older versions
- if vim.g.diagnostics_visible then
- vim.g.diagnostics_visible = false
- vim.lsp.handlers["textDocument/publishDiagnostics"] = function() end
- else
- vim.g.diagnostics_visible = true
- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
- vim.lsp.diagnostic.on_publish_diagnostics, {}
- )
- end
- end
-end
-
--- Create Mason command if Mason is available
-if M.mason then
- vim.api.nvim_create_user_command("Mason", function()
- require("mason.ui").open()
- end, {})
-end
-
--- Automatically show diagnostics in a float window for the current line
-if has_feature("diagnostic_api") then
- vim.api.nvim_create_autocmd("CursorHold", {
- group = augroup_diag_float,
- pattern = "*",
- callback = function()
- local opts = {
- focusable = false,
- close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" },
- border = border,
- source = "always",
- prefix = " ",
- scope = "cursor",
- }
- vim.diagnostic.open_float(nil, opts)
- end,
- })
-
- -- Autocmd to open the diagnostic window when a file with errors is opened
- vim.api.nvim_create_autocmd({ "LspAttach", "BufReadPost" }, {
- group = augroup_diag_load,
- callback = function()
- local has_errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR }) > 0
- if has_errors then
- vim.diagnostic.setqflist({
- open = true,
- title = "Diagnostics",
- })
- end
- end,
- })
-end
-
--- Create Toggle Diagnostic command
-vim.api.nvim_create_user_command("ToggleDiagnostics", _G.toggle_diagnostics, {
- desc = "Toggle global diagnostics visibility"
-})
-
-return M