refactor(LSP): use the new vim.lsp.* functions to set up LSP servers
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
vim.loader.enable()
|
||||
|
||||
local utils = require("ow.utils")
|
||||
local log = require("ow.log")
|
||||
|
||||
local files = {
|
||||
"globals",
|
||||
@@ -13,28 +13,19 @@ for _, file in ipairs(files) do
|
||||
local pkg = "ow.core." .. file
|
||||
local ok, err = pcall(require, pkg)
|
||||
if not ok then
|
||||
utils.err("Error while loading package " .. pkg)
|
||||
utils.err(err)
|
||||
log.error("Error while loading package " .. pkg)
|
||||
log.error(err)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local ok, err = pcall(require, "ow.bootstrap")
|
||||
if not ok then
|
||||
utils.err("Error during bootstrap")
|
||||
utils.err(err:gsub("\t", " "))
|
||||
log.error("Error during bootstrap")
|
||||
log.error(err:gsub("\t", " "))
|
||||
return
|
||||
end
|
||||
|
||||
---@type LazyPluginSpec[]
|
||||
local plugins = {
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
config = require("ow.lsp").setup,
|
||||
},
|
||||
{ import = "ow.plugins" },
|
||||
}
|
||||
|
||||
---@type LazyConfig
|
||||
local opts = {
|
||||
install = {
|
||||
@@ -69,4 +60,4 @@ local opts = {
|
||||
},
|
||||
}
|
||||
|
||||
require("lazy").setup(plugins, opts)
|
||||
require("lazy").setup("ow.plugins", opts)
|
||||
|
||||
+17
-15
@@ -1,34 +1,36 @@
|
||||
{
|
||||
"Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" },
|
||||
"LuaSnip": { "branch": "master", "commit": "03c8e67eb7293c404845b3982db895d59c0d1538" },
|
||||
"aerial.nvim": { "branch": "master", "commit": "2e00d1d4248f08dddfceacb8d2996e51e13e00f6" },
|
||||
"LuaSnip": { "branch": "master", "commit": "458560534a73f7f8d7a11a146c801db00b081df0" },
|
||||
"aerial.nvim": { "branch": "master", "commit": "5c0df1679bf7c814c924dc6646cc5291daca8363" },
|
||||
"catppuccin": { "branch": "main", "commit": "5b5e3aef9ad7af84f463d17b5479f06b87d5c429" },
|
||||
"cmp-cmdline": { "branch": "main", "commit": "d250c63aa13ead745e3a40f61fdd3470efde3923" },
|
||||
"cmp-cmdline": { "branch": "main", "commit": "d126061b624e0af6c3a556428712dd4d4194ec6d" },
|
||||
"cmp-nvim-lsp": { "branch": "main", "commit": "a8912b88ce488f411177fc8aed358b04dc246d7b" },
|
||||
"cmp-path": { "branch": "main", "commit": "c6635aae33a50d6010bf1aa756ac2398a2d54c32" },
|
||||
"cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" },
|
||||
"fidget.nvim": { "branch": "main", "commit": "0ba1e16d07627532b6cae915cc992ecac249fb97" },
|
||||
"friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" },
|
||||
"gitsigns.nvim": { "branch": "main", "commit": "ee28ba3e70ecea811b8f6d7b51d81976e94b121c" },
|
||||
"gitsigns.nvim": { "branch": "main", "commit": "d0f90ef51d4be86b824b012ec52ed715b5622e51" },
|
||||
"lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" },
|
||||
"lspkind.nvim": { "branch": "master", "commit": "d79a1c3299ad0ef94e255d045bed9fa26025dab6" },
|
||||
"mason.nvim": { "branch": "main", "commit": "fc98833b6da5de5a9c5b1446ac541577059555be" },
|
||||
"mason.nvim": { "branch": "main", "commit": "8024d64e1330b86044fed4c8494ef3dcd483a67c" },
|
||||
"nvim-cmp": { "branch": "main", "commit": "b5311ab3ed9c846b585c0c15b7559be131ec4be9" },
|
||||
"nvim-colorizer.lua": { "branch": "master", "commit": "517df88cf2afb36652830df2c655df2da416a0ae" },
|
||||
"nvim-dap": { "branch": "master", "commit": "8df427aeba0a06c6577dc3ab82de3076964e3b8d" },
|
||||
"nvim-lspconfig": { "branch": "master", "commit": "94d0fec9135719e046903bbbbf8f39e3d3436d4e" },
|
||||
"nvim-dap": { "branch": "master", "commit": "ea82027c3447dc1a022be9a9884de276c05cd33a" },
|
||||
"nvim-lspconfig": { "branch": "master", "commit": "036885e8e5456d3907626b634693234f628afef6" },
|
||||
"nvim-notify": { "branch": "master", "commit": "b5825cf9ee881dd8e43309c93374ed5b87b7a896" },
|
||||
"nvim-tree.lua": { "branch": "master", "commit": "582ae48c9e43d2bcd55dfcc8e2e7a1f29065d924" },
|
||||
"nvim-treesitter": { "branch": "master", "commit": "94ea4f436d2b59c80f02e293466c374584f03b8c" },
|
||||
"nvim-treesitter-context": { "branch": "master", "commit": "6daca3ad780f045550b820f262002f35175a6c04" },
|
||||
"nvim-web-devicons": { "branch": "master", "commit": "50b5b06bff13a9b4eab946de7c7033649a6618a1" },
|
||||
"oil.nvim": { "branch": "master", "commit": "685cdb4ffa74473d75a1b97451f8654ceeab0f4a" },
|
||||
"onedark.nvim": { "branch": "master", "commit": "0e5512d1bebd1f08954710086f87a5caa173a924" },
|
||||
"orgmode": { "branch": "master", "commit": "15d66ead1285d99f8a21c4ef4874ac62e9320fe6" },
|
||||
"nvim-tree.lua": { "branch": "master", "commit": "1c733e8c1957dc67f47580fe9c458a13b5612d5b" },
|
||||
"nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
|
||||
"nvim-treesitter-context": { "branch": "master", "commit": "464a443b5a6657f39772b20baa95d02ffe97b268" },
|
||||
"nvim-web-devicons": { "branch": "master", "commit": "1fb58cca9aebbc4fd32b086cb413548ce132c127" },
|
||||
"oil.nvim": { "branch": "master", "commit": "08c2bce8b00fd780fb7999dbffdf7cd174e896fb" },
|
||||
"onedark.nvim": { "branch": "master", "commit": "11de4da47f3e69cb70c3ae9816bd8af166cbe121" },
|
||||
"orgmode": { "branch": "master", "commit": "32ef9e95f43a6e951fb931b438372546a4f0c524" },
|
||||
"plenary.nvim": { "branch": "master", "commit": "857c5ac632080dba10aae49dba902ce3abf91b35" },
|
||||
"telescope-fzf-native.nvim": { "branch": "main", "commit": "1f08ed60cafc8f6168b72b80be2b2ea149813e55" },
|
||||
"telescope.nvim": { "branch": "master", "commit": "a4ed82509cecc56df1c7138920a1aeaf246c0ac5" },
|
||||
"telescope-undo.nvim": { "branch": "main", "commit": "928d0c2dc9606e01e2cc547196f48d2eaecf58e5" },
|
||||
"telescope.nvim": { "branch": "master", "commit": "b4da76be54691e854d3e0e02c36b0245f945c2c7" },
|
||||
"tokyonight.nvim": { "branch": "main", "commit": "057ef5d260c1931f1dffd0f052c685dcd14100a3" },
|
||||
"undotree": { "branch": "master", "commit": "b951b87b46c34356d44aa71886aecf9dd7f5788a" },
|
||||
"vim-flog": { "branch": "master", "commit": "665b16ac8915f746bc43c9572b4581a5e9047216" },
|
||||
"vim-fugitive": { "branch": "master", "commit": "4a745ea72fa93bb15dd077109afbb3d1809383f2" },
|
||||
"vim-ucl": { "branch": "main", "commit": "efbcab5f98b663dbc3cac92801a90b11869c23d0" }
|
||||
|
||||
@@ -6,20 +6,20 @@ if version.major == 0 then
|
||||
end
|
||||
end
|
||||
|
||||
local utils = require("ow.utils")
|
||||
local util = require("ow.util")
|
||||
|
||||
-- Install lazy.nvim
|
||||
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
|
||||
if not vim.uv.fs_stat(lazypath) then
|
||||
utils.assert_installed("git")
|
||||
util.assert_installed("git")
|
||||
if not os.getenv("CC") then
|
||||
utils.assert_installed("cc")
|
||||
util.assert_installed("cc")
|
||||
end
|
||||
utils.assert_installed("make")
|
||||
utils.assert_any_installed({ "curl", "wget", })
|
||||
utils.assert_installed("unzip")
|
||||
utils.assert_installed("tar")
|
||||
utils.assert_installed("gzip")
|
||||
util.assert_installed("make")
|
||||
util.assert_any_installed({ "curl", "wget", })
|
||||
util.assert_installed("unzip")
|
||||
util.assert_installed("tar")
|
||||
util.assert_installed("gzip")
|
||||
|
||||
local resp = vim.system({
|
||||
"git",
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
local M = {}
|
||||
|
||||
--- Log error message
|
||||
---@param fmt string
|
||||
---@param ... any
|
||||
function M.error(fmt, ...)
|
||||
vim.notify(
|
||||
fmt:format(...),
|
||||
vim.log.levels.ERROR
|
||||
)
|
||||
end
|
||||
|
||||
--- Log warning message
|
||||
---@param fmt string
|
||||
---@param ... any
|
||||
function M.warning(fmt, ...)
|
||||
vim.notify(
|
||||
fmt:format(...),
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
end
|
||||
|
||||
--- Log info message
|
||||
---@param fmt string
|
||||
---@param ... any
|
||||
function M.info(fmt, ...)
|
||||
vim.notify(
|
||||
fmt:format(...),
|
||||
vim.log.levels.INFO
|
||||
)
|
||||
end
|
||||
|
||||
--- Log debug message
|
||||
---@param fmt string
|
||||
---@param ... any
|
||||
function M.debug(fmt, ...)
|
||||
vim.notify(
|
||||
fmt:format(...),
|
||||
vim.log.levels.DEBUG
|
||||
)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
+394
-115
@@ -1,12 +1,11 @@
|
||||
local utils = require("ow.utils")
|
||||
---@type fun(name: string, cfg: vim.lsp.Config)
|
||||
vim.lsp.config = vim.lsp.config
|
||||
|
||||
local CONFIG_DIR = vim.fn.stdpath("config") .. "/lua/ow/lsp/config"
|
||||
local keymap = require("ow.lsp.keymap")
|
||||
local linter = require("ow.lsp.linter")
|
||||
local log = require("ow.log")
|
||||
local util = require("ow.util")
|
||||
|
||||
---@class Server
|
||||
local Server = require("ow.lsp.server")
|
||||
|
||||
---@class LSP
|
||||
---@field diagnostic_signs vim.diagnostic.Opts.Signs
|
||||
local M = {}
|
||||
|
||||
M.diagnostic_signs = {
|
||||
@@ -18,122 +17,54 @@ M.diagnostic_signs = {
|
||||
},
|
||||
}
|
||||
|
||||
---@type table<string, Server>
|
||||
local servers = {}
|
||||
---@param fn? fun(client: vim.lsp.Client, bufnr: integer)
|
||||
---@return fun(client: vim.lsp.Client, bufnr: integer)
|
||||
function M.with_defaults(fn)
|
||||
return function(client, bufnr)
|
||||
keymap.set_defaults(bufnr)
|
||||
|
||||
function M.get_servers()
|
||||
return servers
|
||||
end
|
||||
-- For document highlight
|
||||
vim.cmd.highlight({ "link LspReferenceRead Visual", bang = true })
|
||||
vim.cmd.highlight({ "link LspReferenceText Visual", bang = true })
|
||||
vim.cmd.highlight({ "link LspReferenceWrite Visual", bang = true })
|
||||
|
||||
local function get_module_name(filepath)
|
||||
return filepath:match("([^/\\]+)%.lua$")
|
||||
end
|
||||
client.settings = M.with_file(
|
||||
string.format(".%s.json", client.name),
|
||||
client.settings
|
||||
) or client.settings
|
||||
|
||||
local function get_server_config(name)
|
||||
local module = "ow.lsp.config." .. name
|
||||
package.loaded[module] = nil
|
||||
return utils.try_require("ow.lsp.config." .. name)
|
||||
end
|
||||
|
||||
local reload_server_config = utils.debounce_with_id(function(name, events)
|
||||
utils.info(("Reloading server with new config"):format(name), name)
|
||||
---@type Server|nil
|
||||
local server = servers[name]
|
||||
|
||||
if server and server.config.enable then
|
||||
server:deinit()
|
||||
servers[name] = nil
|
||||
end
|
||||
|
||||
if events.rename then
|
||||
local _, _, err_name =
|
||||
vim.uv.fs_stat(("%s/%s.lua"):format(CONFIG_DIR, name))
|
||||
if err_name == "ENOENT" then
|
||||
return
|
||||
if fn then
|
||||
fn(client, bufnr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local config = get_server_config(name)
|
||||
if not config then
|
||||
--- Load a JSON file and return a parsed table merged with settings
|
||||
---@param path string
|
||||
---@param settings? table
|
||||
---@return table?
|
||||
function M.with_file(path, settings)
|
||||
local file = io.open(path, "r")
|
||||
if not file then
|
||||
return
|
||||
end
|
||||
|
||||
server = Server.new(name, config)
|
||||
if not server or not server.config.enable then
|
||||
return
|
||||
end
|
||||
|
||||
local on_done = function(success)
|
||||
if success then
|
||||
utils.info(("%s reloaded"):format(name))
|
||||
end
|
||||
end
|
||||
|
||||
if #server:get_ft_buffers() ~= 0 then
|
||||
server:setup(on_done)
|
||||
else
|
||||
server:init(on_done)
|
||||
end
|
||||
|
||||
servers[name] = server
|
||||
end, 1000)
|
||||
|
||||
local function process_change(error, filename, events)
|
||||
if error then
|
||||
utils.err(
|
||||
("Error on change for %s:\n%s"):format(filename, error),
|
||||
"ow.lsp.on_config_change"
|
||||
local json = file:read("*all")
|
||||
file:close()
|
||||
local ok, resp = pcall(
|
||||
vim.json.decode,
|
||||
json,
|
||||
{ luanil = { object = true, array = true } }
|
||||
)
|
||||
if not ok then
|
||||
log.warning("Failed to parse json file %s: %s", path, resp)
|
||||
return
|
||||
end
|
||||
|
||||
local name = get_module_name(filename)
|
||||
if not name or name == "init" then
|
||||
return
|
||||
end
|
||||
|
||||
reload_server_config(name, name, events)
|
||||
return vim.tbl_deep_extend("force", settings or {}, resp)
|
||||
end
|
||||
|
||||
local function load_configs()
|
||||
local handle = vim.uv.fs_scandir(CONFIG_DIR)
|
||||
while handle do
|
||||
local filepath = vim.uv.fs_scandir_next(handle)
|
||||
|
||||
if not filepath then
|
||||
break
|
||||
end
|
||||
|
||||
local name = get_module_name(filepath)
|
||||
|
||||
if name == "init" then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local config = get_server_config(name)
|
||||
|
||||
if not config then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local server = Server.new(name, config)
|
||||
if server then
|
||||
servers[name] = server
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
vim.uv.fs_event_start(
|
||||
vim.uv.new_fs_event(),
|
||||
CONFIG_DIR,
|
||||
{},
|
||||
vim.schedule_wrap(process_change)
|
||||
)
|
||||
end
|
||||
|
||||
--- Setup diagnostics UI
|
||||
local function setup_diagnostics()
|
||||
function M.setup()
|
||||
vim.diagnostic.config({
|
||||
underline = true,
|
||||
signs = M.diagnostic_signs,
|
||||
@@ -155,17 +86,365 @@ local function setup_diagnostics()
|
||||
wrap = false,
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
load_configs()
|
||||
setup_diagnostics()
|
||||
vim.lsp.enable({
|
||||
"bashls",
|
||||
"clangd",
|
||||
"cmake",
|
||||
"gopls",
|
||||
"intelephense",
|
||||
-- "jedi_language_server",
|
||||
"lemminx",
|
||||
"lua_ls",
|
||||
"mesonlsp",
|
||||
-- "phpactor",
|
||||
-- "pyrefly",
|
||||
"pyright",
|
||||
"ruff",
|
||||
"rust_analyzer",
|
||||
"zls",
|
||||
})
|
||||
|
||||
for _, server in pairs(servers) do
|
||||
if server.config.enable then
|
||||
server:init()
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
local cmp_nvim_lsp = util.try_require("cmp_nvim_lsp")
|
||||
if cmp_nvim_lsp then
|
||||
capabilities = vim.tbl_deep_extend(
|
||||
"force",
|
||||
capabilities,
|
||||
cmp_nvim_lsp.default_capabilities()
|
||||
)
|
||||
end
|
||||
|
||||
vim.lsp.config("*", {
|
||||
on_attach = M.with_defaults(),
|
||||
capabilities = capabilities,
|
||||
})
|
||||
|
||||
vim.lsp.config("bashls", {
|
||||
filetypes = {
|
||||
"sh",
|
||||
"bash",
|
||||
"zsh",
|
||||
},
|
||||
on_attach = M.with_defaults(function(_, bufnr)
|
||||
keymap.set(bufnr, {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
util.format({
|
||||
cmd = { "shfmt", "-s", "-i", "4", "-" },
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
})
|
||||
end),
|
||||
})
|
||||
|
||||
vim.lsp.config("clangd", {
|
||||
filetypes = {
|
||||
"c",
|
||||
"cpp",
|
||||
},
|
||||
cmd = {
|
||||
"clangd",
|
||||
"--clang-tidy",
|
||||
"--enable-config",
|
||||
-- Fix for errors in files outside of project
|
||||
-- https://clangd.llvm.org/faq#how-do-i-fix-errors-i-get-when-opening-headers-outside-of-my-project-directory
|
||||
"--compile-commands-dir=build",
|
||||
},
|
||||
single_file_support = true,
|
||||
on_attach = M.with_defaults(function(_, bufnr)
|
||||
keymap.set(bufnr, {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "gs",
|
||||
rhs = vim.cmd.ClangdSwitchSourceHeader,
|
||||
},
|
||||
})
|
||||
end),
|
||||
})
|
||||
|
||||
vim.lsp.config("cmake", {
|
||||
init_options = {
|
||||
buildDirectory = "build",
|
||||
},
|
||||
})
|
||||
|
||||
vim.lsp.config("gopls", {
|
||||
settings = {
|
||||
gopls = {
|
||||
staticcheck = true,
|
||||
semanticTokens = true,
|
||||
},
|
||||
},
|
||||
on_attach = M.with_defaults(function(_, bufnr)
|
||||
keymap.set(bufnr, {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
util.format({
|
||||
cmd = {
|
||||
"golines",
|
||||
"-m",
|
||||
"80",
|
||||
"--shorten-comments",
|
||||
},
|
||||
output = "stdout",
|
||||
})
|
||||
vim.lsp.buf.format({ async = true })
|
||||
end,
|
||||
},
|
||||
})
|
||||
end),
|
||||
})
|
||||
|
||||
vim.lsp.config("intelephense", {
|
||||
settings = {
|
||||
intelephense = {
|
||||
environment = {
|
||||
phpVersion = "8.4",
|
||||
},
|
||||
format = {
|
||||
enable = true,
|
||||
braces = "psr12",
|
||||
},
|
||||
},
|
||||
},
|
||||
on_attach = M.with_defaults(function(_, bufnr)
|
||||
linter.add(bufnr, {
|
||||
cmd = {
|
||||
"phpcs",
|
||||
"--standard=PSR12",
|
||||
"--report=emacs",
|
||||
"-s",
|
||||
"-q",
|
||||
"-",
|
||||
},
|
||||
stdin = true,
|
||||
stdout = true,
|
||||
pattern = "^.+:(%d+):(%d+): (%w+) %- (.*) %((.*)%)$",
|
||||
groups = { "lnum", "col", "severity", "message", "source" },
|
||||
source = "phpcs",
|
||||
severity_map = {
|
||||
error = vim.diagnostic.severity.ERROR,
|
||||
warning = vim.diagnostic.severity.WARN,
|
||||
},
|
||||
zero_idx_col = true,
|
||||
zero_idx_lnum = true,
|
||||
})
|
||||
|
||||
keymap.set(bufnr, {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
vim.lsp.buf.format()
|
||||
util.format({
|
||||
cmd = {
|
||||
"php-cs-fixer",
|
||||
"fix",
|
||||
"%file%",
|
||||
"--quiet",
|
||||
},
|
||||
output = "in_place",
|
||||
ignore_stderr = true,
|
||||
env = { PHP_CS_FIXER_IGNORE_ENV = "1" },
|
||||
})
|
||||
end,
|
||||
},
|
||||
})
|
||||
end),
|
||||
})
|
||||
|
||||
vim.lsp.config("jedi_language_server", {
|
||||
init_options = {
|
||||
completion = {
|
||||
disableSnippets = true,
|
||||
},
|
||||
diagnostics = {
|
||||
enable = true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
vim.lsp.config("lemminx", {
|
||||
init_options = {
|
||||
settings = {
|
||||
xml = {
|
||||
format = {
|
||||
enabled = true, -- is able to format document
|
||||
splitAttributes = true, -- each attribute is formatted onto new line
|
||||
joinCDATALines = false, -- normalize content inside CDATA
|
||||
joinCommentLines = false, -- normalize content inside comments
|
||||
formatComments = true, -- keep comment in relative position
|
||||
joinContentLines = false, -- normalize content inside elements
|
||||
spaceBeforeEmptyCloseLine = true, -- insert whitespace before self closing tag end bracket
|
||||
},
|
||||
validation = {
|
||||
noGrammar = "ignore",
|
||||
enabled = true,
|
||||
schema = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
local lua_library_paths = {
|
||||
vim.env.VIMRUNTIME,
|
||||
}
|
||||
for _, plugin in ipairs(require("lazy").plugins()) do
|
||||
table.insert(lua_library_paths, plugin.dir)
|
||||
end
|
||||
|
||||
vim.lsp.config("lua_ls", {
|
||||
settings = {
|
||||
Lua = {
|
||||
completion = { showWord = "Disable" },
|
||||
runtime = {
|
||||
version = "LuaJIT",
|
||||
path = {
|
||||
"lua/?.lua",
|
||||
"lua/?/init.lua",
|
||||
},
|
||||
pathStrict = true,
|
||||
},
|
||||
workspace = {
|
||||
library = lua_library_paths,
|
||||
checkThirdParty = false,
|
||||
},
|
||||
hint = {
|
||||
enable = false,
|
||||
arrayIndex = "Disable",
|
||||
await = true,
|
||||
paramName = "All",
|
||||
paramType = true,
|
||||
semicolon = "Disable",
|
||||
setType = true,
|
||||
},
|
||||
telemetry = { enable = false },
|
||||
},
|
||||
},
|
||||
on_attach = M.with_defaults(function(_, bufnr)
|
||||
keymap.set(bufnr, {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
util.format({
|
||||
cmd = { "stylua", "-" },
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
mode = "x",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
util.format({
|
||||
cmd = {
|
||||
"stylua",
|
||||
"-",
|
||||
"--range-start",
|
||||
"%byte_start%",
|
||||
"--range-end",
|
||||
"%byte_end%",
|
||||
},
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
})
|
||||
end),
|
||||
})
|
||||
|
||||
vim.lsp.config("mesonlsp", {
|
||||
settings = {
|
||||
others = {
|
||||
disableInlayHints = true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
vim.lsp.config("pyright", {
|
||||
settings = {
|
||||
python = {
|
||||
analysis = {
|
||||
autoSearchPaths = true,
|
||||
diagnosticMode = "openFilesOnly",
|
||||
useLibraryCodeForTypes = true,
|
||||
typeCheckingMode = "strict",
|
||||
stubPath = "stubs",
|
||||
},
|
||||
},
|
||||
pyright = {
|
||||
disableLanguageServices = false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
vim.lsp.config("ruff", {
|
||||
on_attach = M.with_defaults(function(_, bufnr)
|
||||
keymap.set(bufnr, {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
vim.lsp.buf.format()
|
||||
util.format({
|
||||
cmd = {
|
||||
"ruff",
|
||||
"check",
|
||||
"--stdin-filename=%file%",
|
||||
"--select=I",
|
||||
"--fix",
|
||||
"--quiet",
|
||||
"-",
|
||||
},
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
})
|
||||
end),
|
||||
})
|
||||
|
||||
vim.lsp.config("rust_analyzer", {
|
||||
settings = {
|
||||
["rust-analyzer"] = {
|
||||
inlayHints = {
|
||||
chainingHints = {
|
||||
enable = false,
|
||||
},
|
||||
parameterHints = {
|
||||
enable = false,
|
||||
},
|
||||
typeHints = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
vim.lsp.config("zls", {
|
||||
settings = {
|
||||
zls = {
|
||||
warn_style = true,
|
||||
highlight_global_var_declarations = true,
|
||||
inlay_hints_show_variable_type_hints = false,
|
||||
inlay_hints_show_struct_literal_field_type = false,
|
||||
inlay_hints_show_parameter_name = false,
|
||||
inlay_hints_show_builtin = false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
vim.lsp.config("pyrefly", {})
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
local utils = require("ow.utils")
|
||||
|
||||
return {
|
||||
enable = true,
|
||||
dependencies = {
|
||||
"npm",
|
||||
},
|
||||
mason = {
|
||||
"bash-language-server",
|
||||
dependencies = {
|
||||
{ "shellcheck" },
|
||||
{ "shfmt" },
|
||||
},
|
||||
},
|
||||
keymaps = {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
utils.format({
|
||||
cmd = { "shfmt", "-s", "-i", "4", "-" },
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"sh",
|
||||
"bash",
|
||||
"zsh",
|
||||
},
|
||||
cmd = { "bash-language-server", "start" },
|
||||
single_file_support = true,
|
||||
},
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
---@type ServerConfig
|
||||
return {
|
||||
enable = true,
|
||||
mason = { "clangd" },
|
||||
keymaps = {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "gs",
|
||||
rhs = vim.cmd.ClangdSwitchSourceHeader,
|
||||
},
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"c",
|
||||
"cpp",
|
||||
},
|
||||
cmd = {
|
||||
"clangd",
|
||||
"--clang-tidy",
|
||||
"--enable-config",
|
||||
|
||||
-- Fix for errors in files outside of project
|
||||
-- https://clangd.llvm.org/faq#how-do-i-fix-errors-i-get-when-opening-headers-outside-of-my-project-directory
|
||||
"--compile-commands-dir=build",
|
||||
},
|
||||
single_file_support = true,
|
||||
},
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
return {
|
||||
enable = true,
|
||||
dependencies = {
|
||||
"python3",
|
||||
},
|
||||
mason = {
|
||||
name = "cmake-language-server",
|
||||
-- version = "",
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"cmake",
|
||||
},
|
||||
cmd = { "cmake-language-server", },
|
||||
single_file_support = true,
|
||||
init_options = {
|
||||
buildDirectory = "build",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
local utils = require("ow.utils")
|
||||
|
||||
---@type ServerConfig
|
||||
return {
|
||||
enable = true,
|
||||
mason = { "gopls", dependencies = { "golines" } },
|
||||
keymaps = {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
utils.format({
|
||||
cmd = { "golines", "-m", "80", "--shorten-comments" },
|
||||
output = "stdout",
|
||||
})
|
||||
vim.lsp.buf.format({ async = true })
|
||||
end,
|
||||
},
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"go",
|
||||
"gomod",
|
||||
"gowork",
|
||||
"gotmpl",
|
||||
},
|
||||
cmd = { "gopls" },
|
||||
single_file_support = true,
|
||||
settings = {
|
||||
gopls = {
|
||||
staticcheck = true,
|
||||
semanticTokens = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,30 +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 {
|
||||
enable = false,
|
||||
dependencies = {
|
||||
"java",
|
||||
},
|
||||
mason = {
|
||||
"groovy-language-server",
|
||||
},
|
||||
lspconfig = {
|
||||
cmd = {
|
||||
"groovy-language-server",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
return {
|
||||
enable = true,
|
||||
mason = {
|
||||
name = "haskell-language-server",
|
||||
-- version = "",
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = { "haskell", "lhaskell", "cabal", },
|
||||
cmd = { "haskell-language-server-wrapper", "--lsp", },
|
||||
single_file_support = true,
|
||||
settings = {
|
||||
haskell = {
|
||||
cabalFormattingProvider = "cabalfmt",
|
||||
formattingProvider = "ormolu",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
-- spec:
|
||||
-- https://github.com/bmewburn/intelephense-docs/blob/master/installation.md
|
||||
-- https://github.com/bmewburn/vscode-intelephense/blob/master/package.json
|
||||
|
||||
local utils = require("ow.utils")
|
||||
|
||||
---@type ServerConfig
|
||||
return {
|
||||
enable = true,
|
||||
dependencies = {
|
||||
"npm",
|
||||
},
|
||||
mason = { "intelephense", dependencies = { "phpcs" } },
|
||||
linters = {
|
||||
{
|
||||
cmd = {
|
||||
"phpcs",
|
||||
"--standard=PSR12",
|
||||
"--report=emacs",
|
||||
"-s",
|
||||
"-q",
|
||||
"-",
|
||||
},
|
||||
stdin = true,
|
||||
stdout = true,
|
||||
pattern = "^.+:(%d+):(%d+): (%w+) %- (.*) %((.*)%)$",
|
||||
groups = { "lnum", "col", "severity", "message", "source" },
|
||||
source = "phpcs",
|
||||
severity_map = {
|
||||
error = vim.diagnostic.severity.ERROR,
|
||||
warning = vim.diagnostic.severity.WARN,
|
||||
},
|
||||
zero_idx_col = true,
|
||||
zero_idx_lnum = true,
|
||||
},
|
||||
},
|
||||
keymaps = {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
vim.lsp.buf.format()
|
||||
utils.format({
|
||||
cmd = {
|
||||
"php-cs-fixer",
|
||||
"fix",
|
||||
"%file%",
|
||||
"--quiet",
|
||||
},
|
||||
output = "in_place",
|
||||
ignore_stderr = true,
|
||||
env = { PHP_CS_FIXER_IGNORE_ENV = "1" },
|
||||
})
|
||||
end,
|
||||
},
|
||||
},
|
||||
settings_file = ".intelephense.json",
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"php",
|
||||
},
|
||||
cmd = { "intelephense", "--stdio" },
|
||||
single_file_support = true,
|
||||
settings = {
|
||||
intelephense = {
|
||||
environment = {
|
||||
phpVersion = "8.4",
|
||||
},
|
||||
format = {
|
||||
enable = true,
|
||||
braces = "psr12",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
---@type ServerConfig
|
||||
return {
|
||||
mason = { "jedi-language-server" },
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"python",
|
||||
},
|
||||
cmd = { "jedi-language-server" },
|
||||
single_file_support = true,
|
||||
init_options = {
|
||||
completion = {
|
||||
disableSnippets = true,
|
||||
},
|
||||
diagnostics = {
|
||||
enable = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
-- spec: https://github.com/eclipse/lemminx/blob/main/docs/Configuration.md
|
||||
|
||||
return {
|
||||
enable = true,
|
||||
mason = {
|
||||
name = "lemminx",
|
||||
dependencies = { "xmlformatter" },
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"xml",
|
||||
"xsd",
|
||||
"xsl",
|
||||
"xslt",
|
||||
"svg",
|
||||
},
|
||||
cmd = { "lemminx", },
|
||||
single_file_support = true,
|
||||
init_options = {
|
||||
settings = {
|
||||
xml = {
|
||||
format = {
|
||||
enabled = true, -- is able to format document
|
||||
splitAttributes = true, -- each attribute is formatted onto new line
|
||||
joinCDATALines = false, -- normalize content inside CDATA
|
||||
joinCommentLines = false, -- normalize content inside comments
|
||||
formatComments = true, -- keep comment in relative position
|
||||
joinContentLines = false, -- normalize content inside elements
|
||||
spaceBeforeEmptyCloseLine = true, -- insert whitespace before self closing tag end bracket
|
||||
},
|
||||
validation = {
|
||||
noGrammar = "ignore",
|
||||
enabled = true,
|
||||
schema = true,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
-- spec: https://luals.github.io/wiki/settings/
|
||||
local utils = require("ow.utils")
|
||||
|
||||
---@type ServerConfig
|
||||
return {
|
||||
enable = true,
|
||||
dependencies = { "cargo" },
|
||||
mason = {
|
||||
"lua-language-server",
|
||||
post_install = { { cmd = { "cargo", "install", "stylua", "--features", "lua54" } } },
|
||||
},
|
||||
keymaps = {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
utils.format({
|
||||
cmd = { "stylua", "-" },
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
mode = "x",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
utils.format({
|
||||
cmd = {
|
||||
"stylua",
|
||||
"-",
|
||||
"--range-start",
|
||||
"%byte_start%",
|
||||
"--range-end",
|
||||
"%byte_end%",
|
||||
},
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = { "lua" },
|
||||
cmd = { "lua-language-server" },
|
||||
single_file_support = true,
|
||||
settings = {
|
||||
Lua = {
|
||||
completion = { showWord = "Disable" },
|
||||
diagnostics = {
|
||||
-- disable = { "missing-fields" },
|
||||
},
|
||||
runtime = {
|
||||
version = "LuaJIT",
|
||||
path = {
|
||||
-- "?.lua",
|
||||
"?.lua",
|
||||
"?/init.lua",
|
||||
-- "?.lua",
|
||||
-- "lua/?.lua",
|
||||
-- "lua/?/init.lua",
|
||||
-- "?/lua/?.lua",
|
||||
-- "?/lua/?/init.lua",
|
||||
},
|
||||
-- pathStrict = true,
|
||||
},
|
||||
workspace = {
|
||||
library = {
|
||||
vim.env.VIMRUNTIME,
|
||||
"~/repos/awesome-code-doc",
|
||||
"/usr/share/awesome/lib",
|
||||
vim.fn.stdpath("data") .. "/lazy",
|
||||
},
|
||||
checkThirdParty = false,
|
||||
},
|
||||
hint = {
|
||||
enable = false,
|
||||
arrayIndex = "Disable",
|
||||
await = true,
|
||||
paramName = "All",
|
||||
paramType = true,
|
||||
semicolon = "Disable",
|
||||
setType = true,
|
||||
},
|
||||
telemetry = { enable = false },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
---@type ServerConfig
|
||||
return {
|
||||
enable = true,
|
||||
mason = { "mesonlsp" },
|
||||
lspconfig = {
|
||||
---@type fun(filename: string, bufnr: number): string?
|
||||
root_dir = function(filename, bufnr)
|
||||
local parent = require("lspconfig").util.find_git_ancestor(filename)
|
||||
if not parent then
|
||||
local win = vim.fn.bufwinid(bufnr)
|
||||
parent = vim.fn.getcwd(win)
|
||||
end
|
||||
return parent
|
||||
end,
|
||||
settings = {
|
||||
others = {
|
||||
disableInlayHints = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
local util = require("lspconfig.util")
|
||||
|
||||
---@type ServerConfig
|
||||
return {
|
||||
enable = false,
|
||||
dependencies = { "pyrefly" },
|
||||
lspconfig = {
|
||||
cmd = { "pyrefly", "lsp" },
|
||||
filetypes = { "python" },
|
||||
root_dir = util.root_pattern(
|
||||
"pyrefly.toml",
|
||||
"pyproject.toml",
|
||||
"setup.py",
|
||||
"setup.cfg",
|
||||
"requirements.txt",
|
||||
"Pipfile",
|
||||
".git"
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
---@type ServerConfig
|
||||
return {
|
||||
mason = { "pyright" },
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"python",
|
||||
},
|
||||
cmd = { "pyright-langserver", "--stdio" },
|
||||
single_file_support = true,
|
||||
-- https://microsoft.github.io/pyright/#/settings
|
||||
settings = {
|
||||
python = {
|
||||
analysis = {
|
||||
autoSearchPaths = true,
|
||||
diagnosticMode = "openFilesOnly",
|
||||
useLibraryCodeForTypes = true,
|
||||
typeCheckingMode = "strict",
|
||||
stubPath = "stubs",
|
||||
},
|
||||
},
|
||||
pyright = {
|
||||
disableLanguageServices = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
local utils = require("ow.utils")
|
||||
|
||||
---@type ServerConfig
|
||||
return {
|
||||
mason = "ruff",
|
||||
keymaps = {
|
||||
{
|
||||
mode = "n",
|
||||
lhs = "<leader>lf",
|
||||
rhs = function()
|
||||
vim.lsp.buf.format()
|
||||
utils.format({
|
||||
cmd = {
|
||||
"ruff",
|
||||
"check",
|
||||
"--stdin-filename=%file%",
|
||||
"--select=I",
|
||||
"--fix",
|
||||
"--quiet",
|
||||
"-",
|
||||
},
|
||||
output = "stdout",
|
||||
})
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
-- spec: https://rust-analyzer.github.io/manual.html#configuration
|
||||
|
||||
return {
|
||||
enable = true,
|
||||
mason = {
|
||||
name = "rust-analyzer",
|
||||
-- version = "",
|
||||
},
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"rust",
|
||||
},
|
||||
cmd = { "rust-analyzer", },
|
||||
single_file_support = true,
|
||||
settings = {
|
||||
["rust-analyzer"] = {
|
||||
inlayHints = {
|
||||
chainingHints = {
|
||||
enable = false,
|
||||
},
|
||||
parameterHints = {
|
||||
enable = false,
|
||||
},
|
||||
typeHints = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
--[[ assist = {
|
||||
emitMustUse = false,
|
||||
expressionFillDefault = false,
|
||||
},
|
||||
cachePriming = {
|
||||
enable = false,
|
||||
},
|
||||
cargo = {
|
||||
autoreload = false,
|
||||
buildScripts = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
checkOnSave = false,
|
||||
completion = {
|
||||
autoimport = {
|
||||
enable = false,
|
||||
},
|
||||
autoself = {
|
||||
enable = false,
|
||||
},
|
||||
callable = {
|
||||
snippets = false,
|
||||
},
|
||||
fullFunctionSignatures = {
|
||||
enable = false,
|
||||
},
|
||||
postfix = {
|
||||
enable = false,
|
||||
},
|
||||
privateEditable = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
diagnostics = {
|
||||
enable = false,
|
||||
},
|
||||
highlightRelated = {
|
||||
breakPoints = {
|
||||
enable = false,
|
||||
},
|
||||
closureCaptures = {
|
||||
enable = false,
|
||||
},
|
||||
exitPoints = {
|
||||
enable = false,
|
||||
},
|
||||
references = {
|
||||
enable = false,
|
||||
},
|
||||
yieldPoints = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
hover = {
|
||||
actions = {
|
||||
enable = false,
|
||||
},
|
||||
documentation = {
|
||||
enable = true,
|
||||
},
|
||||
links = {
|
||||
enable = false,
|
||||
},
|
||||
memoryLayout = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
imports = {
|
||||
group = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
inlayHints = {
|
||||
bindingModeHints = {
|
||||
enable = false,
|
||||
},
|
||||
chainingHints = {
|
||||
enable = false,
|
||||
},
|
||||
closingBraceHints = {
|
||||
enable = false,
|
||||
},
|
||||
closureCaptureHints = {
|
||||
enable = false,
|
||||
},
|
||||
closureReturnTypeHints = {
|
||||
enable = false,
|
||||
},
|
||||
discriminantHints = {
|
||||
enable = false,
|
||||
},
|
||||
expressionAdjustmentHints = {
|
||||
enable = false,
|
||||
},
|
||||
lifetimeElisionHints = {
|
||||
enable = false,
|
||||
},
|
||||
parameterHints = {
|
||||
enable = false,
|
||||
},
|
||||
reborrowHints = {
|
||||
enable = false,
|
||||
},
|
||||
typeHints = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
joinLines = {
|
||||
joinAssignments = false,
|
||||
joinElseIf = false,
|
||||
removeTrailingComma = false,
|
||||
unwrapTrivialBlock = false,
|
||||
},
|
||||
lens = {
|
||||
enable = false,
|
||||
},
|
||||
notifications = {
|
||||
cargoTomlNotFound = false,
|
||||
},
|
||||
procMacro = {
|
||||
enable = false,
|
||||
},
|
||||
references = {
|
||||
excludeImports = false,
|
||||
},
|
||||
rustfmt = {
|
||||
rangeFormatting = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
semanticHighlighting = {
|
||||
doc = {
|
||||
comment = {
|
||||
inject = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
nonStandardTokens = false,
|
||||
operator = {
|
||||
enable = false,
|
||||
},
|
||||
punctuation = {
|
||||
enable = false,
|
||||
},
|
||||
strings = {
|
||||
enable = false,
|
||||
},
|
||||
},
|
||||
signatureInfo = {
|
||||
documentation = {
|
||||
enable = true,
|
||||
},
|
||||
},
|
||||
typing = {
|
||||
autoClosingAngleBrackets = {
|
||||
enable = false,
|
||||
},
|
||||
}, ]]
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
-- spec: https://github.com/zigtools/zls#configuration-options
|
||||
|
||||
---@type ServerConfig
|
||||
return {
|
||||
enable = true,
|
||||
dependencies = {
|
||||
"zig",
|
||||
},
|
||||
-- mason = {
|
||||
-- name = "zls",
|
||||
-- -- version = "",
|
||||
-- },
|
||||
lspconfig = {
|
||||
filetypes = {
|
||||
"zig",
|
||||
"zir",
|
||||
},
|
||||
cmd = { "zls", },
|
||||
single_file_support = true,
|
||||
settings = {
|
||||
zls = {
|
||||
warn_style = true,
|
||||
highlight_global_var_declarations = true,
|
||||
inlay_hints_show_variable_type_hints = false,
|
||||
inlay_hints_show_struct_literal_field_type = false,
|
||||
inlay_hints_show_parameter_name = false,
|
||||
inlay_hints_show_builtin = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
+19
-55
@@ -1,7 +1,4 @@
|
||||
-- Mappings.
|
||||
-- See `:help vim.lsp.*` for documentation on any of the below functions
|
||||
|
||||
local utils = require("ow.utils")
|
||||
local util = require("ow.util")
|
||||
|
||||
---@class Keymap
|
||||
---@field mode string|string[]
|
||||
@@ -9,29 +6,25 @@ local utils = require("ow.utils")
|
||||
---@field rhs string|function
|
||||
---@field opts? vim.keymap.set.Opts
|
||||
|
||||
local MODE_TYPES = { "n", "v", "s", "x", "o", "i", "l", "c" }
|
||||
|
||||
local M = {}
|
||||
|
||||
---@type table<number, vim.api.keyset.keymap[]>
|
||||
M.old = {}
|
||||
|
||||
---@type table<number, Keymap[]>
|
||||
M.new = {}
|
||||
|
||||
--- Load LSP keybinds
|
||||
---@param server Server
|
||||
function M:init(server, bufnr)
|
||||
self.old[bufnr] = {}
|
||||
for _, mode in ipairs(MODE_TYPES) do
|
||||
vim.tbl_extend(
|
||||
"error",
|
||||
self.old[bufnr],
|
||||
vim.api.nvim_buf_get_keymap(bufnr, mode)
|
||||
---@param bufnr integer
|
||||
---@param keymaps Keymap[]
|
||||
function M.set(bufnr, keymaps)
|
||||
for _, keymap in ipairs(keymaps) do
|
||||
keymap.opts = vim.tbl_extend(
|
||||
"force",
|
||||
keymap.opts or {},
|
||||
{ buffer = bufnr, remap = true }
|
||||
)
|
||||
vim.keymap.set(keymap.mode, keymap.lhs, keymap.rhs, keymap.opts)
|
||||
end
|
||||
end
|
||||
|
||||
self.new[bufnr] = {
|
||||
---@param bufnr integer
|
||||
function M.set_defaults(bufnr)
|
||||
---@type Keymap[]
|
||||
local keymaps = {
|
||||
{ mode = { "n" }, lhs = "<leader>df", rhs = vim.diagnostic.open_float },
|
||||
{
|
||||
mode = { "n" },
|
||||
@@ -88,10 +81,10 @@ function M:init(server, bufnr)
|
||||
},
|
||||
}
|
||||
|
||||
local telescope = utils.try_require("telescope.builtin")
|
||||
local telescope = util.try_require("telescope.builtin")
|
||||
|
||||
if telescope then
|
||||
vim.list_extend(self.new[bufnr], {
|
||||
vim.list_extend(keymaps, {
|
||||
{ mode = "n", lhs = "<leader>dl", rhs = telescope.diagnostics },
|
||||
{ mode = "n", lhs = "grt", rhs = telescope.lsp_type_definitions, },
|
||||
{ mode = "n", lhs = "gd", rhs = telescope.lsp_definitions },
|
||||
@@ -99,43 +92,14 @@ function M:init(server, bufnr)
|
||||
{ mode = "n", lhs = "grr", rhs = telescope.lsp_references },
|
||||
})
|
||||
else
|
||||
vim.list_extend(self.new[bufnr], {
|
||||
vim.list_extend(keymaps, {
|
||||
{ mode = "n", lhs = "<leader>dl", rhs = vim.diagnostic.setloclist },
|
||||
{ mode = "n", lhs = "grt", rhs = vim.lsp.buf.type_definition, },
|
||||
{ mode = "n", lhs = "gd", rhs = vim.lsp.buf.definition },
|
||||
})
|
||||
end
|
||||
|
||||
if server.config.keymaps then
|
||||
vim.list_extend(self.new[bufnr], server.config.keymaps)
|
||||
end
|
||||
|
||||
for _, keymap in ipairs(self.new[bufnr]) do
|
||||
keymap.opts = vim.tbl_extend(
|
||||
"force",
|
||||
keymap.opts or {},
|
||||
{ buffer = bufnr, remap = true }
|
||||
)
|
||||
vim.keymap.set(keymap.mode, keymap.lhs, keymap.rhs, keymap.opts)
|
||||
end
|
||||
end
|
||||
|
||||
function M:deinit(bufnr)
|
||||
if self.new[bufnr] then
|
||||
for _, keymap in ipairs(self.new[bufnr]) do
|
||||
-- pcall to avoid error if keymap was already removed,
|
||||
-- for example if server.config.keymaps overrides a default LSP keymap
|
||||
pcall(vim.keymap.del, keymap.mode, keymap.lhs, { buffer = bufnr })
|
||||
end
|
||||
self.new[bufnr] = nil
|
||||
end
|
||||
|
||||
if self.old[bufnr] then
|
||||
for _, keymap in ipairs(self.old[bufnr]) do
|
||||
vim.cmd.mapset(keymap)
|
||||
end
|
||||
self.old[bufnr] = nil
|
||||
end
|
||||
M.set(bufnr, keymaps)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
+55
-58
@@ -1,10 +1,10 @@
|
||||
local utils = require("ow.utils")
|
||||
local util = require("ow.util")
|
||||
local log = require("ow.log")
|
||||
|
||||
---@class Linter
|
||||
---@field name string
|
||||
---@field namespace number
|
||||
---@field augroup number
|
||||
---@field buffers number[]
|
||||
---@field bufnr number
|
||||
---@field config LinterConfig
|
||||
M = {}
|
||||
M.__index = M
|
||||
@@ -89,10 +89,9 @@ end
|
||||
|
||||
--- Clamp column to line length
|
||||
---@param diag vim.Diagnostic
|
||||
---@param bufnr number
|
||||
function M:clamp_col(diag, bufnr)
|
||||
function M:clamp_col(diag)
|
||||
local lines =
|
||||
vim.api.nvim_buf_get_lines(bufnr, diag.lnum, diag.lnum + 1, false)
|
||||
vim.api.nvim_buf_get_lines(self.bufnr, diag.lnum, diag.lnum + 1, false)
|
||||
if #lines == 0 then
|
||||
return
|
||||
end
|
||||
@@ -160,7 +159,7 @@ function M:fix_indexing(diag)
|
||||
end
|
||||
end
|
||||
|
||||
function M:process_json_output(json, bufnr)
|
||||
function M:process_json_output(json)
|
||||
---@type vim.Diagnostic[]
|
||||
local diagnostics = {}
|
||||
|
||||
@@ -170,7 +169,7 @@ function M:process_json_output(json, bufnr)
|
||||
end
|
||||
|
||||
if type(items) ~= "table" then
|
||||
utils.err("diagnostics root is not an array or object")
|
||||
log.error("diagnostics root is not an array or object")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -198,7 +197,7 @@ function M:process_json_output(json, bufnr)
|
||||
end
|
||||
|
||||
self:fix_indexing(diag)
|
||||
self:clamp_col(diag, bufnr)
|
||||
self:clamp_col(diag)
|
||||
self:add_tags(diag)
|
||||
|
||||
if type(self.config.json.callback) == "function" then
|
||||
@@ -212,12 +211,10 @@ function M:process_json_output(json, bufnr)
|
||||
end
|
||||
|
||||
--- Validate input
|
||||
---@param name string
|
||||
---@param config LinterConfig
|
||||
---@return boolean
|
||||
function M.validate(name, config)
|
||||
function M.validate(config)
|
||||
local ok, resp = pcall(vim.validate, {
|
||||
name = { name, "string" },
|
||||
config = { config, "table" },
|
||||
})
|
||||
|
||||
@@ -226,7 +223,7 @@ function M.validate(name, config)
|
||||
cmd = {
|
||||
config.cmd,
|
||||
function(t)
|
||||
return utils.is_list(t, "string")
|
||||
return util.is_list(t, "string")
|
||||
end,
|
||||
"list of strings",
|
||||
},
|
||||
@@ -237,7 +234,7 @@ function M.validate(name, config)
|
||||
groups = {
|
||||
config.groups,
|
||||
function(t)
|
||||
return utils.is_list(t, "string")
|
||||
return util.is_list(t, "string")
|
||||
end,
|
||||
true,
|
||||
"list of strings",
|
||||
@@ -245,7 +242,7 @@ function M.validate(name, config)
|
||||
severity_map = {
|
||||
config.severity_map,
|
||||
function(t)
|
||||
return utils.is_map(t, "string", "number")
|
||||
return util.is_map(t, "string", "number")
|
||||
end,
|
||||
true,
|
||||
"map of string and number",
|
||||
@@ -258,23 +255,24 @@ function M.validate(name, config)
|
||||
end
|
||||
|
||||
if not ok then
|
||||
utils.err(("Invalid config for linter:\n%s"):format(resp))
|
||||
log.error("Invalid config for linter: %s", resp)
|
||||
return false
|
||||
end
|
||||
|
||||
if not config.json and (not config.pattern or not config.groups) then
|
||||
utils.err("Either json or pattern and groups must be provided")
|
||||
log.error("Either json or pattern and groups must be provided")
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function M:run(bufnr)
|
||||
---@return boolean success
|
||||
function M:run()
|
||||
local input
|
||||
|
||||
if self.config.stdin then
|
||||
input = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||
input = vim.api.nvim_buf_get_lines(self.bufnr, 0, -1, false)
|
||||
end
|
||||
|
||||
local cmd = vim.fn.copy(self.config.cmd)
|
||||
@@ -286,6 +284,7 @@ function M:run(bufnr)
|
||||
cmd[i] = arg
|
||||
end
|
||||
|
||||
local success = true
|
||||
local ok, resp = pcall(
|
||||
vim.system,
|
||||
cmd,
|
||||
@@ -301,7 +300,7 @@ function M:run(bufnr)
|
||||
if self.config.stderr then
|
||||
output = out.stderr or ""
|
||||
elseif out.stderr and out.stderr ~= "" then
|
||||
utils.err(out.stderr)
|
||||
log.error(out.stderr)
|
||||
end
|
||||
|
||||
if self.config.json then
|
||||
@@ -311,13 +310,14 @@ function M:run(bufnr)
|
||||
{ luanil = { object = true, array = true } }
|
||||
)
|
||||
if not ok then
|
||||
utils.err("Failed to parse JSON: " .. json)
|
||||
log.error("Failed to parse JSON: " .. json)
|
||||
success = false
|
||||
return
|
||||
end
|
||||
|
||||
local diagnostics = self:process_json_output(json, bufnr)
|
||||
local diagnostics = self:process_json_output(json)
|
||||
if diagnostics then
|
||||
vim.diagnostic.set(self.namespace, bufnr, diagnostics)
|
||||
vim.diagnostic.set(self.namespace, self.bufnr, diagnostics)
|
||||
end
|
||||
|
||||
return
|
||||
@@ -335,67 +335,64 @@ function M:run(bufnr)
|
||||
)
|
||||
|
||||
if not ok then
|
||||
utils.err(tostring(resp))
|
||||
log.error(tostring(resp))
|
||||
success = false
|
||||
return
|
||||
elseif resp then
|
||||
resp.source = resp.source or self.config.source
|
||||
self:clamp_col(resp, bufnr)
|
||||
self:clamp_col(resp)
|
||||
self:add_tags(resp)
|
||||
self:fix_indexing(resp)
|
||||
table.insert(diagnostics, resp)
|
||||
end
|
||||
end
|
||||
|
||||
vim.diagnostic.set(self.namespace, bufnr, diagnostics)
|
||||
vim.diagnostic.set(self.namespace, self.bufnr, diagnostics)
|
||||
end)
|
||||
)
|
||||
|
||||
if not ok then
|
||||
utils.err(("Failed to run %s:\n%s"):format(self.config.cmd[1], resp))
|
||||
log.error("Failed to run %s: %s", self.config.cmd[1], resp)
|
||||
success = false
|
||||
end
|
||||
|
||||
return success
|
||||
end
|
||||
|
||||
function M:init(bufnr)
|
||||
table.insert(self.buffers, bufnr)
|
||||
vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
|
||||
buffer = bufnr,
|
||||
callback = utils.debounce(function()
|
||||
self:run(bufnr)
|
||||
end, self.config.debounce),
|
||||
group = self.augroup,
|
||||
})
|
||||
self:run(bufnr)
|
||||
end
|
||||
|
||||
function M:deinit()
|
||||
for _, bufnr in ipairs(self.buffers) do
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, self.namespace, 0, -1)
|
||||
end
|
||||
self.buffers = {}
|
||||
|
||||
vim.api.nvim_clear_autocmds({ group = self.augroup })
|
||||
end
|
||||
|
||||
--- Create a new instance
|
||||
---@param name string
|
||||
---@param bufnr integer
|
||||
---@param config LinterConfig
|
||||
---@return Linter|nil
|
||||
function M.new(name, config)
|
||||
if not M.validate(name, config) then
|
||||
function M.add(bufnr, config)
|
||||
if not M.validate(config) then
|
||||
return
|
||||
end
|
||||
|
||||
config.debounce = config.debounce or 100
|
||||
|
||||
local linter = {
|
||||
name = name,
|
||||
namespace = vim.api.nvim_create_namespace(name),
|
||||
augroup = vim.api.nvim_create_augroup(name, {}),
|
||||
buffers = {},
|
||||
namespace = vim.api.nvim_create_namespace("ow.lsp.linter"),
|
||||
augroup = vim.api.nvim_create_augroup(
|
||||
"ow.lsp.linter",
|
||||
{ clear = false }
|
||||
),
|
||||
bufnr = bufnr,
|
||||
config = config,
|
||||
}
|
||||
|
||||
return setmetatable(linter, M)
|
||||
linter = setmetatable(linter, M)
|
||||
|
||||
local success = linter:run()
|
||||
if not success then
|
||||
log.error("Not adding linter because of previous errors")
|
||||
return
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
|
||||
buffer = linter.bufnr,
|
||||
callback = util.debounce(function()
|
||||
linter:run()
|
||||
end, linter.config.debounce),
|
||||
group = linter.augroup,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
local utils = require("ow.utils")
|
||||
|
||||
---@class PostInstallStep
|
||||
---@field cmd string[]
|
||||
|
||||
---@class MasonPackage
|
||||
---@field dependencies? MasonPackage[]
|
||||
---@field config MasonPackageConfig
|
||||
local M = {}
|
||||
M.__index = M
|
||||
|
||||
---@class MasonPackageConfig
|
||||
---@field [1]? string
|
||||
---@field name? string
|
||||
---@field version? string
|
||||
---@field dependencies? string[]|MasonPackageConfig[]
|
||||
---@field post_install? PostInstallStep[]
|
||||
M.config = {}
|
||||
|
||||
--- Validate MasonPackageConfig
|
||||
---@param config string|MasonPackageConfig
|
||||
---@return boolean
|
||||
function M.validate(config)
|
||||
local ok, resp = pcall(vim.validate, { config = { config, { "table" } } })
|
||||
if ok then
|
||||
ok, resp = pcall(vim.validate, {
|
||||
name = { config.name or config[1], { "string" }, true },
|
||||
version = { config.version, { "string" }, true },
|
||||
dependencies = {
|
||||
config.dependencies,
|
||||
function(f)
|
||||
if not f then
|
||||
return true
|
||||
end
|
||||
|
||||
for _, dep in ipairs(f) do
|
||||
local t = type(dep)
|
||||
if
|
||||
(t ~= "string" and t ~= "table")
|
||||
or (type(dep) == "table" and not M.validate(dep))
|
||||
then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end,
|
||||
"list of string|MasonPackageConfig",
|
||||
},
|
||||
post_install = {
|
||||
config.post_install,
|
||||
function(field)
|
||||
if not field then
|
||||
return true
|
||||
end
|
||||
|
||||
if not utils.is_list(field) then
|
||||
return false
|
||||
end
|
||||
|
||||
for _, step in ipairs(field) do
|
||||
local o, r = pcall(vim.validate, { step = { step, { "table" } } })
|
||||
if o then
|
||||
o, r = pcall(vim.validate, {
|
||||
cmd = {
|
||||
step.cmd,
|
||||
function(f)
|
||||
return utils.is_list(f, "string")
|
||||
end,
|
||||
"list of strings or nil",
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
if not o then
|
||||
utils.err(("Invalid config for post_install step: %s"):format(r), "LSP")
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
end,
|
||||
"list of steps",
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
if not ok then
|
||||
utils.err(
|
||||
("Invalid config for %s:\n%s"):format(config.name or config[1] or config, resp),
|
||||
"LSP"
|
||||
)
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Run post installation steps
|
||||
---@param pkg Package
|
||||
function M:post_install(pkg)
|
||||
---@param step PostInstallStep
|
||||
---@param msg string
|
||||
local function log_err(step, msg)
|
||||
local cmd = table.concat(step.cmd, " ")
|
||||
|
||||
utils.err(
|
||||
("Post installation step for %s:\n`%s`\nfailed with:\n%s"):format(
|
||||
self.config.name,
|
||||
cmd,
|
||||
msg
|
||||
),
|
||||
"LSP"
|
||||
)
|
||||
end
|
||||
|
||||
if self.config.post_install then
|
||||
for _, step in ipairs(self.config.post_install) do
|
||||
utils.info("running post install step", "LSP")
|
||||
local cwd = pkg:get_install_path()
|
||||
local args = step.cmd
|
||||
local prog = table.remove(args, 1)
|
||||
|
||||
if prog:find("[/\\]") then
|
||||
prog = vim.fn.resolve(("%s/%s"):format(cwd, prog))
|
||||
end
|
||||
|
||||
if not utils.is_executable(prog) then
|
||||
log_err(step, "command not executable")
|
||||
return
|
||||
end
|
||||
|
||||
local job = require("plenary.job"):new({
|
||||
command = prog,
|
||||
args = args,
|
||||
cwd = pkg:get_install_path(),
|
||||
enabled_recording = true,
|
||||
on_exit = vim.schedule_wrap(function(job, code, signal)
|
||||
if code ~= 0 or signal ~= 0 then
|
||||
log_err(step, table.concat(job:stderr_result(), "\n"))
|
||||
return
|
||||
end
|
||||
utils.info("post install step done", "LSP")
|
||||
end),
|
||||
})
|
||||
job:start()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Handle installation
|
||||
---@param pkg Package
|
||||
---@param old_version? string
|
||||
---@param new_version? string
|
||||
---@param on_done? fun(success: boolean)
|
||||
function M:handle_install(pkg, old_version, new_version, on_done)
|
||||
local version_str = ""
|
||||
if old_version and new_version then
|
||||
version_str = (" %s -> %s"):format(old_version, new_version)
|
||||
elseif new_version then
|
||||
version_str = " " .. new_version
|
||||
end
|
||||
|
||||
utils.info(("Installing %s%s"):format(self.config.name, version_str), "LSP")
|
||||
local handle = pkg:install({ version = new_version })
|
||||
local err
|
||||
handle:on(
|
||||
"stderr",
|
||||
vim.schedule_wrap(function(msg)
|
||||
err = (err or "") .. msg
|
||||
end)
|
||||
)
|
||||
|
||||
handle:once(
|
||||
"closed",
|
||||
vim.schedule_wrap(function()
|
||||
local is_installed = pkg:is_installed()
|
||||
|
||||
if is_installed then
|
||||
utils.info(("Successfully installed %s"):format(self.config.name), "LSP")
|
||||
self:post_install(pkg)
|
||||
else
|
||||
if err then
|
||||
err = ":\n" .. err
|
||||
else
|
||||
err = ""
|
||||
end
|
||||
|
||||
utils.err(("Failed to install %s%s"):format(self.config.name, err), "LSP")
|
||||
end
|
||||
|
||||
if on_done then
|
||||
on_done(is_installed)
|
||||
end
|
||||
end)
|
||||
)
|
||||
end
|
||||
|
||||
--- Perform installation
|
||||
---@param on_done fun(success: boolean)?
|
||||
function M:install(on_done)
|
||||
local registry = require("mason-registry")
|
||||
local success, result = pcall(registry.get_package, self.config.name)
|
||||
|
||||
if not success then
|
||||
utils.err(("Failed to get package %s:\n%s"):format(self.config.name, result), "LSP")
|
||||
|
||||
if on_done then
|
||||
on_done(false)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local pkg = result
|
||||
|
||||
if not pkg:is_installed() then
|
||||
self:handle_install(pkg, nil, self.config.version, on_done)
|
||||
elseif self.config.version then
|
||||
pkg:get_installed_version(function(ok, version_or_err)
|
||||
if not ok then
|
||||
utils.err(
|
||||
("Failed to check currently installed version for %s:\n%s"):format(
|
||||
self.config.name,
|
||||
version_or_err
|
||||
),
|
||||
"LSP"
|
||||
)
|
||||
elseif self.config.version ~= version_or_err then
|
||||
self:handle_install(pkg, version_or_err, self.config.version, on_done)
|
||||
return
|
||||
end
|
||||
|
||||
if on_done then
|
||||
on_done(ok)
|
||||
end
|
||||
end)
|
||||
else
|
||||
pkg:check_new_version(function(update_available, res)
|
||||
local ok = type(res) == "table" or res == "Package is not outdated."
|
||||
|
||||
if not ok then
|
||||
utils.err(
|
||||
("Failed to check for update for %s:\n%s"):format(self.config.name, res),
|
||||
"LSP"
|
||||
)
|
||||
elseif update_available then
|
||||
self:handle_install(pkg, res.current_version, res.latest_version, on_done)
|
||||
return
|
||||
end
|
||||
|
||||
if on_done then
|
||||
on_done(ok)
|
||||
end
|
||||
end)
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--- Install package dependencies
|
||||
---@param on_done fun(success: boolean)?
|
||||
function M:install_dependencies(on_done)
|
||||
local total = #self.dependencies
|
||||
local completed = 0
|
||||
local all_successful = true
|
||||
|
||||
--- Handle install result
|
||||
---@param success boolean
|
||||
local function handle_result(success)
|
||||
completed = completed + 1
|
||||
|
||||
if not success then
|
||||
all_successful = false
|
||||
end
|
||||
|
||||
if completed == total and on_done then
|
||||
on_done(all_successful)
|
||||
end
|
||||
end
|
||||
|
||||
for _, dep in ipairs(self.dependencies) do
|
||||
dep:install_with_dependencies(handle_result)
|
||||
end
|
||||
end
|
||||
|
||||
--- Install package and any defined dependencies
|
||||
---@param on_done fun(success: boolean)?
|
||||
function M:install_with_dependencies(on_done)
|
||||
--- Handle install result
|
||||
---@param success boolean
|
||||
local function handle_result(success)
|
||||
if success then
|
||||
self:install(on_done)
|
||||
elseif on_done then
|
||||
on_done(success)
|
||||
end
|
||||
end
|
||||
|
||||
require("mason-registry").refresh(function()
|
||||
if self.dependencies and #self.dependencies ~= 0 then
|
||||
self:install_dependencies(handle_result)
|
||||
else
|
||||
self:install(on_done)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Create a new instance
|
||||
---@param config MasonPackageConfig|string
|
||||
---@return MasonPackage|nil
|
||||
function M.new(config)
|
||||
if type(config) == "string" then
|
||||
config = { config }
|
||||
end
|
||||
|
||||
if not M.validate(config) then
|
||||
return
|
||||
end
|
||||
|
||||
config.name = config.name or config[1]
|
||||
|
||||
local pkg = { config = config }
|
||||
|
||||
if pkg.config.dependencies then
|
||||
pkg.dependencies = {}
|
||||
|
||||
for _, dep_cfg in ipairs(config.dependencies) do
|
||||
local dep = M.new(dep_cfg)
|
||||
if dep then
|
||||
table.insert(pkg.dependencies, dep)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return setmetatable(pkg, M)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,392 +0,0 @@
|
||||
local keymap = require("ow.lsp.keymap")
|
||||
local utils = require("ow.utils")
|
||||
|
||||
---@class Linter
|
||||
local Linter = require("ow.lsp.linter")
|
||||
|
||||
---@class MasonPackage
|
||||
local MasonPackage = require("ow.lsp.package")
|
||||
|
||||
---@class Server
|
||||
---@field name? string
|
||||
---@field mason? MasonPackage
|
||||
---@field client? vim.lsp.Client
|
||||
---@field attached_buffers? number[]
|
||||
---@field manager lspconfig.Manager
|
||||
---@field linters? Linter[]
|
||||
---@field config ServerConfig
|
||||
local M = {}
|
||||
|
||||
M.__index = M
|
||||
|
||||
---@class ServerConfig
|
||||
---@field enable? boolean
|
||||
---@field dependencies? string[]
|
||||
---@field mason? string|MasonPackageConfig
|
||||
---@field keymaps? Keymap[]
|
||||
---@field linters? LinterConfig[]
|
||||
---@field settings_file? string
|
||||
---@field lspconfig? lspconfig.Config
|
||||
M.config = {}
|
||||
|
||||
--- Validate ServerConfig
|
||||
---@param config ServerConfig
|
||||
---@return boolean
|
||||
function M.validate(name, config)
|
||||
local ok, resp = pcall(vim.validate, { config = { config, { "table" } } })
|
||||
|
||||
if ok then
|
||||
ok, resp = pcall(vim.validate, {
|
||||
enable = { config.enable, { "boolean" }, true },
|
||||
dependencies = {
|
||||
config.dependencies,
|
||||
function(f)
|
||||
return utils.is_list_or_nil(f, "string")
|
||||
end,
|
||||
"list of strings or nil",
|
||||
},
|
||||
mason = { config.mason, { "string", "table" }, true },
|
||||
keymaps = {
|
||||
config.keymaps,
|
||||
function(f)
|
||||
if not f then
|
||||
return true
|
||||
end
|
||||
|
||||
if not utils.is_list(f, "table") then
|
||||
return false
|
||||
end
|
||||
|
||||
for _, key in ipairs(f) do
|
||||
local o, r = pcall(vim.validate, {
|
||||
mode = { key.mode, { "string", "table" } },
|
||||
lhs = { key.lhs, "string" },
|
||||
rhs = { key.rhs, { "string", "function" } },
|
||||
opts = { key.opts, "table", true },
|
||||
})
|
||||
|
||||
if not o then
|
||||
utils.err(("Invalid keymap:\n%s"):format(r))
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end,
|
||||
"list of keymaps",
|
||||
},
|
||||
lspconfig = { config.lspconfig, { "table" }, true },
|
||||
})
|
||||
end
|
||||
|
||||
if not ok then
|
||||
utils.err(("Invalid config for %s:\n%s"):format(name, resp))
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Called when language server attaches
|
||||
---@param client vim.lsp.Client
|
||||
---@param bufnr integer
|
||||
function M:on_attach(client, bufnr)
|
||||
if self.client and self.client.id ~= client.id then
|
||||
self.client:stop(true)
|
||||
end
|
||||
self.client = client
|
||||
self.attached_buffers = self.attached_buffers or {}
|
||||
table.insert(self.attached_buffers, bufnr)
|
||||
|
||||
keymap:init(self, bufnr)
|
||||
if self.linters then
|
||||
for _, linter in ipairs(self.linters) do
|
||||
local bin = linter.config.cmd[1]
|
||||
if utils.is_executable(bin) then
|
||||
linter:init(bufnr)
|
||||
else
|
||||
utils.warn(
|
||||
("Not adding %s because it is not installed"):format(bin)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- For document highlight
|
||||
vim.cmd.highlight({ "link LspReferenceRead Visual", bang = true })
|
||||
vim.cmd.highlight({ "link LspReferenceText Visual", bang = true })
|
||||
vim.cmd.highlight({ "link LspReferenceWrite Visual", bang = true })
|
||||
|
||||
---@alias lsp.Client vim.lsp.Client
|
||||
-- require("lsp_compl").attach(client, bufnr, {
|
||||
-- server_side_fuzzy_completion = true,
|
||||
-- })
|
||||
end
|
||||
|
||||
--- Configure the LSP client
|
||||
function M:configure_client()
|
||||
local lspconfig = require("lspconfig")
|
||||
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
local cmp_nvim_lsp = utils.try_require("cmp_nvim_lsp")
|
||||
if cmp_nvim_lsp then
|
||||
capabilities = vim.tbl_deep_extend(
|
||||
"force",
|
||||
capabilities,
|
||||
cmp_nvim_lsp.default_capabilities()
|
||||
)
|
||||
end
|
||||
|
||||
-- local epo = utils.try_require("epo")
|
||||
-- if epo then
|
||||
-- capabilities = vim.tbl_deep_extend(
|
||||
-- "force",
|
||||
-- capabilities,
|
||||
-- epo.register_cap()
|
||||
-- )
|
||||
-- end
|
||||
|
||||
-- local lsp_compl = utils.try_require("lsp_compl")
|
||||
-- if lsp_compl then
|
||||
-- capabilities = vim.tbl_deep_extend("force", capabilities, lsp_compl.capabilities())
|
||||
-- end
|
||||
--
|
||||
|
||||
self.config.lspconfig.capabilities = capabilities
|
||||
self.config.lspconfig.on_attach = function(client, bufnr)
|
||||
local ok, ret = pcall(self.on_attach, self, client, bufnr)
|
||||
if not ok then
|
||||
utils.err(
|
||||
("Failed to load on_attach for %s:\n%s"):format(self.name, ret),
|
||||
"lsp.server:configure_client"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
if self.config.settings_file then
|
||||
local file = io.open(self.config.settings_file, "r")
|
||||
if not file then
|
||||
utils.warn(
|
||||
("Failed to open file for reading: %s"):format(
|
||||
self.config.settings_file
|
||||
)
|
||||
)
|
||||
else
|
||||
local json = file:read("*all")
|
||||
file:close()
|
||||
local ok, resp = pcall(
|
||||
vim.json.decode,
|
||||
json,
|
||||
{ luanil = { object = true, array = true } }
|
||||
)
|
||||
if not ok then
|
||||
utils.warn(
|
||||
("Failed to parse json file %s:%s"):format(
|
||||
self.config.settings_file,
|
||||
resp
|
||||
)
|
||||
)
|
||||
else
|
||||
self.config.lspconfig.settings = vim.tbl_deep_extend(
|
||||
"force",
|
||||
self.config.lspconfig.settings or {},
|
||||
resp
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ok, ret = pcall(lspconfig[self.name].setup, self.config.lspconfig)
|
||||
if not ok then
|
||||
utils.err(
|
||||
("Failed to setup LSP server %s with lspconfig: %s"):format(
|
||||
self.name,
|
||||
ret
|
||||
)
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
self.manager = lspconfig[self.name].manager
|
||||
for _, bufnr in ipairs(self:get_ft_buffers()) do
|
||||
self.manager:try_add_wrapper(bufnr)
|
||||
end
|
||||
|
||||
if self.config.linters then
|
||||
self.linters = {}
|
||||
for i, config in ipairs(self.config.linters) do
|
||||
local linter =
|
||||
Linter.new(("%s_linter%d"):format(self.name, i), config)
|
||||
|
||||
if linter then
|
||||
table.insert(self.linters, linter)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M:get_ft_buffers()
|
||||
local filetypes = self.config.lspconfig.filetypes or {}
|
||||
if not vim.list_contains(filetypes, self.config.lspconfig.filetype) then
|
||||
table.insert(filetypes, self.config.lspconfig.filetype)
|
||||
end
|
||||
if #filetypes == 0 then
|
||||
return {}
|
||||
end
|
||||
return vim.tbl_filter(function(bufnr)
|
||||
return vim.list_contains(filetypes, vim.bo[bufnr].filetype)
|
||||
end, vim.api.nvim_list_bufs())
|
||||
end
|
||||
|
||||
--- Check for and return missing dependencies
|
||||
---@return table<string>
|
||||
function M:get_missing_unmanaged_deps()
|
||||
local missing_deps = {}
|
||||
if self.config.dependencies ~= nil then
|
||||
for _, dep in ipairs(self.config.dependencies) do
|
||||
if not utils.is_executable(dep) then
|
||||
table.insert(missing_deps, dep)
|
||||
end
|
||||
end
|
||||
end
|
||||
return missing_deps
|
||||
end
|
||||
|
||||
--- Install LSP server
|
||||
---@param on_done fun(success: boolean)?
|
||||
function M:install(on_done)
|
||||
--- Handle install result
|
||||
---@param success boolean
|
||||
local function handle_result(success)
|
||||
if not success then
|
||||
self.config.enable = false
|
||||
end
|
||||
if on_done then
|
||||
on_done(success)
|
||||
end
|
||||
end
|
||||
|
||||
self.mason:install_with_dependencies(handle_result)
|
||||
end
|
||||
|
||||
--- Setup LSP server
|
||||
function M:setup(on_done)
|
||||
local missing_deps = self:get_missing_unmanaged_deps()
|
||||
|
||||
if #missing_deps > 0 then
|
||||
utils.warn(
|
||||
(
|
||||
"Disabling %s because the following package(s)"
|
||||
.. "are not installed: %s"
|
||||
):format(self.name, table.concat(missing_deps, ", "))
|
||||
)
|
||||
self.config.enable = false
|
||||
return
|
||||
end
|
||||
|
||||
if self.mason then
|
||||
self:install(function(success)
|
||||
if success then
|
||||
self:configure_client()
|
||||
end
|
||||
|
||||
if on_done then
|
||||
on_done(success)
|
||||
end
|
||||
end)
|
||||
elseif vim.fn.executable(self.config.lspconfig.cmd[1]) == 1 then
|
||||
self:configure_client()
|
||||
else
|
||||
utils.warn(self.name .. " not installed, disabling")
|
||||
self.config.enable = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Load autocmd for setting up LSP server upon entering a buffer of related
|
||||
--- filetype
|
||||
function M:init(on_done)
|
||||
local group = vim.api.nvim_create_augroup("lsp_bootstrap_" .. self.name, {})
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
once = true,
|
||||
pattern = self.config.lspconfig.filetypes or {},
|
||||
callback = function()
|
||||
self:setup(on_done)
|
||||
end,
|
||||
group = group,
|
||||
})
|
||||
end
|
||||
|
||||
function M:deinit()
|
||||
if self.attached_buffers then
|
||||
for _, bufnr in ipairs(self.attached_buffers) do
|
||||
keymap:deinit(bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
if self.client then
|
||||
self.client:stop(true)
|
||||
self.client = nil
|
||||
end
|
||||
|
||||
vim.api.nvim_clear_autocmds({ group = "lsp_bootstrap_" .. self.name })
|
||||
|
||||
if self.linters then
|
||||
for _, linter in ipairs(self.linters) do
|
||||
linter:deinit()
|
||||
end
|
||||
|
||||
self.linters = nil
|
||||
end
|
||||
|
||||
require("lspconfig.configs")[self.name] = nil
|
||||
require("lspconfig")[self.name] = nil
|
||||
end
|
||||
|
||||
--- Create a new instance
|
||||
---@param name string
|
||||
---@param config? ServerConfig
|
||||
---@return Server|nil
|
||||
function M.new(name, config)
|
||||
config = config or {}
|
||||
|
||||
if config.enable == nil then
|
||||
config.enable = true
|
||||
end
|
||||
|
||||
if not M.validate(name, config) then
|
||||
return
|
||||
end
|
||||
|
||||
local ok, resp = pcall(require, "lspconfig.configs." .. name)
|
||||
if not ok and config.lspconfig then
|
||||
require("lspconfig.configs")[name] = vim.tbl_deep_extend(
|
||||
"keep",
|
||||
{ default_config = {} },
|
||||
config.lspconfig
|
||||
)
|
||||
elseif ok then
|
||||
config.lspconfig = vim.tbl_deep_extend(
|
||||
"keep",
|
||||
config.lspconfig or {},
|
||||
resp.default_config
|
||||
)
|
||||
else
|
||||
utils.err(
|
||||
("Server with name %s does not exist in lspconfig"):format(name)
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
local server = { name = name, config = config }
|
||||
|
||||
if server.config.mason then
|
||||
local pkg = MasonPackage.new(server.config.mason)
|
||||
if pkg then
|
||||
server.mason = pkg
|
||||
end
|
||||
end
|
||||
|
||||
return setmetatable(server, M)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -38,7 +38,7 @@ return {
|
||||
require("luasnip.loaders.from_vscode").lazy_load()
|
||||
end,
|
||||
build = (
|
||||
require("ow.utils").os_name ~= "Windows_NT"
|
||||
require("ow.util").os_name ~= "Windows_NT"
|
||||
and "make install_jsregexp"
|
||||
or nil
|
||||
),
|
||||
@@ -55,7 +55,6 @@ return {
|
||||
config = function()
|
||||
local cmp = require("cmp")
|
||||
local luasnip = require("luasnip")
|
||||
local utils = require("ow.utils")
|
||||
local lspkind = require("lspkind")
|
||||
|
||||
---@type cmp.ConfigSchema
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---@type LazyPluginSpec
|
||||
return {
|
||||
"neovim/nvim-lspconfig",
|
||||
config = require("ow.lsp").setup,
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
local utils = require("ow.utils")
|
||||
local util = require("ow.util")
|
||||
|
||||
local function override_highlights()
|
||||
-- File Icon
|
||||
local hl = utils.get_hl_source("NvimTreeFileIcon")
|
||||
local hl = util.get_hl_source("NvimTreeFileIcon")
|
||||
vim.api.nvim_set_hl(0, "NvimTreeFileIcon", { fg = hl.fg, bg = nil })
|
||||
|
||||
-- Symlink Icon
|
||||
hl = utils.get_hl_source("NvimTreeSymlinkIcon")
|
||||
hl = util.get_hl_source("NvimTreeSymlinkIcon")
|
||||
vim.api.nvim_set_hl(0, "NvimTreeSymlinkIcon", { fg = hl.fg, bg = nil })
|
||||
end
|
||||
|
||||
|
||||
@@ -97,34 +97,6 @@ function M.assert_python3_module_installed(mod)
|
||||
end
|
||||
end
|
||||
|
||||
--- Send a debug notification
|
||||
---@param msg string Message to send
|
||||
---@param title? string Title of notification
|
||||
function M.debug(msg, title)
|
||||
notify(msg, title, vim.log.levels.DEBUG)
|
||||
end
|
||||
|
||||
--- Send an info notification
|
||||
---@param msg string Message to send
|
||||
---@param title? string Title of notification
|
||||
function M.info(msg, title)
|
||||
notify(msg, title, vim.log.levels.INFO)
|
||||
end
|
||||
|
||||
--- Send a warning notification
|
||||
---@param msg string Message to send
|
||||
---@param title? string Title of notification
|
||||
function M.warn(msg, title)
|
||||
notify(msg, title, vim.log.levels.WARN)
|
||||
end
|
||||
|
||||
--- Send an error notification
|
||||
---@param msg string Message to send
|
||||
---@param title? string Title of notification
|
||||
function M.err(msg, title)
|
||||
notify(msg, title, vim.log.levels.ERROR)
|
||||
end
|
||||
|
||||
--- Attempts to load a module and logs errors on failure.
|
||||
---@param module string The module to attempt to load.
|
||||
---@return any module The loaded module if successful, otherwise nil.
|
||||
Reference in New Issue
Block a user