diff --git a/init.lua b/init.lua index cb7e638..8c3a0c8 100644 --- a/init.lua +++ b/init.lua @@ -14,14 +14,18 @@ limitations under the License. ]] +local module_name = "base" + +local utils = require("utils") + local files = { "globals", "options", "autocommands", "mappings", } for _, file in ipairs(files) do local pkg = "core." .. file local ok, err = pcall(require, pkg) if not ok then - print("Error while loading package " .. pkg) - print(err) + utils.err("Error while loading package " .. pkg, module_name) + utils.err(err, module_name) return end end @@ -31,15 +35,15 @@ if vim.g.vscode then else local ok, err = pcall(require, "bootstrap") if not ok then - print("Error during bootstrap") - print(err:gsub("\t", " ")) + utils.err("Error during bootstrap", module_name) + utils.err(err:gsub("\t", " "), module_name) return end ok, err = pcall(require, "plugins") if not ok then - print("Error while loading plugins") - print(err:gsub("\t", " ")) + utils.err("Error while loading plugins", module_name) + utils.err(err:gsub("\t", " "), module_name) return end end diff --git a/lua/config/nvim-notify.lua b/lua/config/nvim-notify.lua new file mode 100644 index 0000000..ec15633 --- /dev/null +++ b/lua/config/nvim-notify.lua @@ -0,0 +1,2 @@ +vim.notify = require("notify") +require("telescope").load_extension("notify") diff --git a/lua/lsp/config/golangci_lint_ls.lua b/lua/lsp/config/golangci_lint_ls.lua deleted file mode 100644 index 29b4050..0000000 --- a/lua/lsp/config/golangci_lint_ls.lua +++ /dev/null @@ -1,22 +0,0 @@ ---[[ - Copyright 2023 Oscar Wallberg - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -]] - -return { - cmd = { "golangci-lint-langserver", }, - init_options = { - command = { "golangci-lint", "run", "--out-format", "json", }, - }, -} diff --git a/lua/lsp/config/gopls.lua b/lua/lsp/config/gopls.lua deleted file mode 100644 index 07cb525..0000000 --- a/lua/lsp/config/gopls.lua +++ /dev/null @@ -1,84 +0,0 @@ ---[[ - Copyright 2023 Oscar Wallberg - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -]] - -return { - cmd = { "gopls", "serve", }, - -- https://github.com/golang/tools/blob/master/gopls/doc/settings.md - settings = { - gopls = { - gofumpt = true, - codelenses = { - gc_details = true, - generate = true, - regenerate_cgo = true, - run_vulncheck_exp = true, - tidy = true, - upgrade_dependency = true, - vendor = true, - }, - usePlaceholders = true, - analyses = { - asmdecl = true, - assign = true, - atomic = true, - atomicalign = true, - bools = true, - buildtag = true, - cgocall = true, - composites = true, - copylocks = true, - deepequalerrors = true, - embed = true, - errorsas = true, - fieldalignment = true, - httpresponse = true, - ifaceassert = true, - infertypeargs = true, - loopclosure = true, - lostcancel = true, - nilfunc = true, - nilness = true, - printf = true, - shadow = true, - shift = true, - simplifycompositelit = true, - simplifyrange = true, - simplifyslice = true, - sortslice = true, - stdmethods = true, - stringintconv = true, - structtag = true, - testinggoroutine = true, - tests = true, - timeformat = true, - unmarshal = true, - unreachable = true, - unsafeptr = true, - unusedparams = true, - unusedresult = true, - unusedwrite = true, - useany = true, - fillreturns = true, - nonewvars = true, - noresultvalues = true, - undeclaredname = true, - unusedvariable = true, - fillstruct = true, - stubmethods = true, - }, - }, - }, -} diff --git a/lua/lsp/config/pylsp.lua b/lua/lsp/config/pylsp.lua deleted file mode 100644 index 8e47e4f..0000000 --- a/lua/lsp/config/pylsp.lua +++ /dev/null @@ -1,61 +0,0 @@ ---[[ - Copyright 2023 Oscar Wallberg - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -]] - -return { - cmd = { "pylsp", }, - single_file_support = true, - -- Reference: https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md - settings = { - pylsp = { - -- configurationSources = { "flake8", "jedi_completion", "jedi_definition", "jedi_hover", "jedi_references", "jedi_signature_help", "jedi_symbols" }, - plugins = { - flake8 = { - config = "tox.ini", - enabled = true, - -- executable = "flake8" - }, - pyls_isort = { enabled = true, }, - jedi_completion = { - enabled = true, - include_params = false, - include_class_objects = true, - fuzzy = true, - eager = true, - resolve_at_most = 25, - cache_for = { - "pandas", - "numpy", - "tensorflow", - "matplotlib", - }, - }, - jedi_definition = { - enabled = true, - follow_imports = true, - follow_builtin_imports = true, - }, - jedi_hover = { enabled = true, }, - jedi_references = { enabled = true, }, - jedi_signature_help = { enabled = true, }, - jedi_symbols = { - enabled = true, - all_scopes = true, - include_import_symbols = true, - }, - }, - }, - }, -} diff --git a/lua/lsp/config/pyright.lua b/lua/lsp/config/pyright.lua deleted file mode 100644 index f35ee49..0000000 --- a/lua/lsp/config/pyright.lua +++ /dev/null @@ -1,39 +0,0 @@ ---[[ - Copyright 2023 Oscar Wallberg - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -]] - -return { - cmd = { "pyright-langserver", "--stdio", }, - single_file_support = true, - -- see https://github.com/microsoft/pyright/blob/main/docs/configuration.md - -- and https://github.com/fannheyward/coc-pyright - settings = { - python = { - disableCompletion = false, - disableDiagnostics = false, - analysis = { - autoImportCompletions = true, - autoSearchPaths = true, - diagnosticMode = "workspace", - stubPath = "typings", - typeschedPaths = {}, - diagnosticSeverityOverrides = {}, - typeCheckingMode = "off", - useLibraryCodeForTypes = true, - }, - completion = { importSupport = true, snippetSupport = true, }, - }, - }, -} diff --git a/lua/lsp/config/rust_analyzer.lua b/lua/lsp/config/rust_analyzer.lua deleted file mode 100644 index 4871b39..0000000 --- a/lua/lsp/config/rust_analyzer.lua +++ /dev/null @@ -1,38 +0,0 @@ ---[[ - Copyright 2023 Oscar Wallberg - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -]] - -return { - cmd = { "rust-analyzer", }, - settings = { - -- https://github.com/rust-lang/rust-analyzer/blob/master/docs/user/generated_config.adoc - ["rust-analyzer"] = { - cargo = { - -- Extra environment variables that will be set when running cargo, rustc - -- or other commands within the workspace. Useful for setting RUSTFLAGS. - extraEnv = { - OPENSSL_INCLUDE_DIR = "/usr/include/openssl-1.0/", - OPENSSL_LIB_DIR = "/usr/lib/openssl-1.0/", - }, - }, - --[[ inlayHints = { - closingBraceHints = { - -- Whether to show inlay hints after a closing `}` to indicate what item it belongs to. - enable = false - }, - } ]] - }, - }, -} diff --git a/lua/lsp/init.lua b/lua/lsp/init.lua index c50f1ba..4ced1b0 100644 --- a/lua/lsp/init.lua +++ b/lua/lsp/init.lua @@ -14,6 +14,9 @@ limitations under the License. ]] +local module_name = "lsp" +local utils = require("utils") + local P = {} P._filetypes = nil @@ -21,7 +24,7 @@ P._language_servers = nil P.capabilities = {} -P.spec = require("lsp.spec") +P.servers = require("lsp.servers") function P._setup_diagnostic() vim.diagnostic.config({ @@ -216,9 +219,9 @@ function P.on_attach(client, bufnr) end function P.reload_server_buf(self, name) - local server_spec = self.spec[name] + local server = self.servers[name] local ft_map = {} - for _, ft in ipairs(server_spec.filetypes) do + for _, ft in ipairs(server.filetypes) do ft_map[ft] = true end for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do @@ -238,8 +241,8 @@ function P.filetypes(self) if not self._filetypes then self._filetypes = {} local unique = {} - for _, server_spec in pairs(self.spec) do - for _, ft in ipairs(server_spec.filetypes) do + for _, cfg in pairs(self.servers) do + for _, ft in ipairs(cfg.filetypes) do if not unique[ft] then table.insert(self._filetypes, ft) unique[ft] = true @@ -254,23 +257,41 @@ end function P.language_servers(self) if not self._language_servers then self._language_servers = {} - for server, _ in pairs(self.spec) do - table.insert(self._language_servers, server) + for name, opts in pairs(self.servers) do + if opts.dependencies ~= nil then + for _, dep in ipairs(opts.dependencies) do + if not utils.is_available(dep) then + utils.warn("Disabling " .. name .. " because " .. dep .. " is required but not installed", + module_name) + opts.enabled = false + end + end + end + + if opts.enabled == true then + opts.config = require("lsp.config." .. name) + table.insert(self._language_servers, name) + end end end return self._language_servers end -function P.setup_server(self, server) +function P.setup_server(self, name) + local opts = self.servers[name] + + if opts.enabled ~= true then + return + end + local lspconfig = require("lspconfig") - local server_spec = self.spec[server] - local cfg = require("lsp.config." .. server) - cfg.filetypes = server_spec.filetypes - cfg.root_dir = lspconfig.util.find_git_ancestor - cfg.capabilities = self.capabilities - cfg.on_attach = self.on_attach - lspconfig[server].setup(cfg) + opts.config.filetypes = opts.filetypes + opts.config.root_dir = lspconfig.util.find_git_ancestor + opts.config.capabilities = self.capabilities + opts.config.on_attach = self.on_attach + lspconfig[name].setup(opts.config) + self:reload_server_buf(name) end function P.setup(self) @@ -279,7 +300,6 @@ function P.setup(self) require("mason-lspconfig").setup_handlers({ function (name) self:setup_server(name) - self:reload_server_buf(name) end, }) end diff --git a/lua/lsp/spec.lua b/lua/lsp/servers.lua similarity index 75% rename from lua/lsp/spec.lua rename to lua/lsp/servers.lua index df12687..592fcfa 100644 --- a/lua/lsp/spec.lua +++ b/lua/lsp/servers.lua @@ -14,8 +14,9 @@ limitations under the License. ]] -return { +local servers = { clangd = { + enabled = true, filetypes = { "c", "cpp", @@ -24,25 +25,36 @@ return { "cuda", "proto", }, + config = {}, }, cmake = { + enabled = true, filetypes = { "cmake", }, + config = {}, }, diagnosticls = { + enabled = true, filetypes = { "python", "lua", "sh", }, + dependencies = { + "npm", + }, + config = {}, }, lua_ls = { + enabled = true, filetypes = { "lua", }, + config = {}, }, lemminx = { + enabled = true, filetypes = { "xml", "xsd", @@ -50,39 +62,32 @@ return { "xslt", "svg", }, + config = {}, }, bashls = { + enabled = true, filetypes = { "sh", }, + dependencies = { + "npm", + }, + config = {}, }, groovyls = { + enabled = true, filetypes = { "groovy", }, - }, - rust_analyzer = { - filetypes = { - "rust", - }, - }, - gopls = { - filetypes = { - "go", - "gomod", - }, - }, - golangci_lint_ls = { - filetypes = { - "go", - "gomod", - }, + config = {}, }, jedi_language_server = { + enabled = true, filetypes = { "python", }, + config = {}, }, - -- pyright = { 'python' }, - -- pylsp = { 'python' }, } + +return servers diff --git a/lua/plugins.lua b/lua/plugins.lua index 7da2415..5122cc1 100644 --- a/lua/plugins.lua +++ b/lua/plugins.lua @@ -23,6 +23,11 @@ local plugins = { lazy = false, config = function () require("config.vscode") end, }, + { + "rcarriga/nvim-notify", + priority = 900, + config = function () require("config.nvim-notify") end, + }, { "rafamadriz/friendly-snippets", }, diff --git a/lua/utils.lua b/lua/utils.lua index 835f681..728039a 100644 --- a/lua/utils.lua +++ b/lua/utils.lua @@ -43,7 +43,7 @@ end --- @param exe string: Array to look for function M.assert_available(exe) if not M.is_available(exe) then - error("Missing executable '" .. exe .. "'.") + M.notify("Missing executable '" .. exe .. "'.") end end @@ -65,4 +65,27 @@ function M.assert_python3_module(mod) end end +function M.notify(msg, title, level) + if title and not pcall(require, "notify") then + msg = "[" .. title .. "] " .. msg + end + vim.notify(msg, level, { title = title, }) +end + +function M.debug(msg, title) + M.notify(msg, title, vim.log.levels.DEBUG) +end + +function M.info(msg, title) + M.notify(msg, title, vim.log.levels.INFO) +end + +function M.warn(msg, title) + M.notify(msg, title, vim.log.levels.WARN) +end + +function M.err(msg, title) + M.notify(msg, title, vim.log.levels.ERROR) +end + return M