Compare commits

..

10 commits

Author SHA1 Message Date
Simon Lasbrugnas
e2d837067c
chore: update dependencies
Some checks failed
release-please / release-please (push) Has been cancelled
2026-02-03 09:55:36 +01:00
Simon Lasbrugnas
4db3637929
feat(lua_ls): enable love2d third party library 2026-02-02 17:15:12 +01:00
Simon Lasbrugnas
b9acc5db52
chore: increase conform timeout to 500ms 2026-02-02 17:11:50 +01:00
Simon Lasbrugnas
a2e5555c64
fix(lsp)!: actually use the root lsp/ folder and remove
lua/custom/lsp/** configs

This commit removes the need for nvim-lspconfig which is replaced by the
vim.lsp API.

The lsp/ folder is a copy of nvim-lspconfig's lsp/ folder as it makes it
easy to modify LSP configurations on the fly.

Conform: biome has been replaced with oxfmt
2026-02-02 16:16:06 +01:00
Simon Lasbrugnas
98ea058690
chore: update dependencies 2026-01-26 11:55:56 +01:00
Simon Lasbrugnas
ecfa9a363a
feat: replace trouble plugin with vim.diagnostic 2026-01-23 19:15:28 +01:00
Simon Lasbrugnas
5ca4f0ef5b
feat(conform): add terraform fmt 2026-01-23 19:01:13 +01:00
Simon Lasbrugnas
8a58f7fe3c
chore: update dependencies 2026-01-20 09:40:01 +01:00
Simon Lasbrugnas
13fafde824
feat: add git diff keymaps 2026-01-19 18:04:23 +01:00
Simon Lasbrugnas
1b295597f4
fix(fugitive): disable lsp in diff buffers 2026-01-19 16:37:55 +01:00
101 changed files with 1661 additions and 561 deletions

View file

@ -1,62 +1,60 @@
{
"Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" },
"LuaSnip": { "branch": "master", "commit": "3732756842a2f7e0e76a7b0487e9692072857277" },
"adwaita.nvim": { "branch": "main", "commit": "334d918d5241262816624e8c80410574ccdb25dc" },
"avante.nvim": { "branch": "main", "commit": "a27b821cc1f9fec70d7b7dc4a42c6dbd76266997" },
"LuaSnip": { "branch": "master", "commit": "dae4f5aaa3574bd0c2b9dd20fb9542a02c10471c" },
"adwaita.nvim": { "branch": "main", "commit": "93f3bed009f7fc4c57f8d710880b6cab9e0b0d15" },
"avante.nvim": { "branch": "main", "commit": "e89eb79abf5754645e20aa6074da10ed20bba33c" },
"cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" },
"cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" },
"cmp-nvim-lua": { "branch": "main", "commit": "e3a22cb071eb9d6508a156306b102c45cd2d573d" },
"cmp-path": { "branch": "main", "commit": "c642487086dbd9a93160e1679a1327be111cbc25" },
"cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" },
"conform.nvim": { "branch": "master", "commit": "8314f4c9e205e7f30b62147069729f9a1227d8bf" },
"conform.nvim": { "branch": "master", "commit": "c2526f1cde528a66e086ab1668e996d162c75f4f" },
"dressing.nvim": { "branch": "master", "commit": "2d7c2db2507fa3c4956142ee607431ddb2828639" },
"format-ts-errors.nvim": { "branch": "main", "commit": "4b7418d6689bc0fd3c1db0500c67133422522384" },
"fzf-lua": { "branch": "main", "commit": "a03d68e40eea835a1cdbd9f93049708dab3621e6" },
"fzf-lua": { "branch": "main", "commit": "696f8c071723f845b904af2f99a798650210355e" },
"github-nvim-theme": { "branch": "main", "commit": "c106c9472154d6b2c74b74565616b877ae8ed31d" },
"gitsigns.nvim": { "branch": "main", "commit": "dfac404ac94b0eb1461bd7da32279e16950dfd67" },
"gitsigns.nvim": { "branch": "main", "commit": "42d6aed4e94e0f0bbced16bbdcc42f57673bd75e" },
"go.nvim": { "branch": "master", "commit": "41a18f0c05534c375bafec7ed05cdb409c4abcc6" },
"gruvbox": { "branch": "master", "commit": "697c00291db857ca0af00ec154e5bd514a79191f" },
"hybrid.nvim": { "branch": "master", "commit": "74dfee0d5084a3db5e2ad0a78a67ee45e93a64bf" },
"img-clip.nvim": { "branch": "main", "commit": "b6ddfb97b5600d99afe3452d707444afda658aca" },
"indent-blankline.nvim": { "branch": "master", "commit": "005b56001b2cb30bfa61b7986bc50657816ba4ba" },
"kanagawa-paper.nvim": { "branch": "master", "commit": "1352e3cb3a5a017cb1ab49056643ae4d2fddb0cf" },
"kanagawa-paper.nvim": { "branch": "master", "commit": "c85d672cc9a6d968771dc6f2203c1dc2bade6ff2" },
"lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
"lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" },
"lsp-zero.nvim": { "branch": "v4.x", "commit": "d388e2b71834c826e61a3eba48caec53d7602510" },
"lsp_signature.nvim": { "branch": "master", "commit": "7d3bb0a641f516f1c7fd2e47852580dadbd7a430" },
"lspkind.nvim": { "branch": "master", "commit": "3ddd1b4edefa425fda5a9f95a4f25578727c0bb3" },
"lspkind.nvim": { "branch": "master", "commit": "53374a2dbcb959f1d0d5d3cf6c47c4b029151c6e" },
"lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" },
"lush.nvim": { "branch": "main", "commit": "9c60ec2279d62487d942ce095e49006af28eed6e" },
"luvit-meta": { "branch": "main", "commit": "0ea4ff636c5bb559ffa78108561d0976f4de9682" },
"mason-lspconfig.nvim": { "branch": "main", "commit": "4cfe411526a7a99c18281135e8b4765ae6330d15" },
"mason-lspconfig.nvim": { "branch": "main", "commit": "80c0130c5f16b551865a69e832f1feadeedb5fbe" },
"mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" },
"mason.nvim": { "branch": "main", "commit": "57e5a8addb8c71fb063ee4acda466c7cf6ad2800" },
"mason.nvim": { "branch": "main", "commit": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65" },
"mellow.nvim": { "branch": "main", "commit": "5cd188489bcc7eb512f0a30581ad972070f8e5cd" },
"neodev.nvim": { "branch": "main", "commit": "46aa467dca16cf3dfe27098042402066d2ae242d" },
"neovim-ayu": { "branch": "master", "commit": "38caa8b5b969010b1dcae8ab1a569d7669a643d5" },
"neovim-ayu": { "branch": "master", "commit": "e5a9f0fa2918d6b5f57c21b3ac014314ee5e41c8" },
"nightfox.nvim": { "branch": "main", "commit": "ba47d4b4c5ec308718641ba7402c143836f35aa9" },
"nord.nvim": { "branch": "master", "commit": "80c1e5321505aeb22b7a9f23eb82f1e193c12470" },
"nordic.nvim": { "branch": "main", "commit": "4f0245ed32a32436b2c6ae1a03f625a93a8c077a" },
"nordic.nvim": { "branch": "main", "commit": "962c717820a9d7201ef7622cf1e78bd57806bb7c" },
"nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" },
"nvim-cmp": { "branch": "main", "commit": "85bbfad83f804f11688d1ab9486b459e699292d6" },
"nvim-dap": { "branch": "master", "commit": "cdfd55a133f63228c55f91378f12908cb2a78ded" },
"nvim-dap-ui": { "branch": "master", "commit": "cf91d5e2d07c72903d052f5207511bf7ecdb7122" },
"nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" },
"nvim-lint": { "branch": "master", "commit": "1e6b2ac034d1a7588d11b0b8e862a7ad89368376" },
"nvim-lspconfig": { "branch": "master", "commit": "0b38bc74487e73489624d61396af7805af9cc75f" },
"nvim-lspconfig": { "branch": "master", "commit": "92ee7d42320edfbb81f3cad851314ab197fa324a" },
"nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" },
"nvim-treesitter": { "branch": "main", "commit": "b033ab331ca0bccbd93c3c2b4f886fdfc09abec0" },
"nvim-treesitter": { "branch": "main", "commit": "e75c007f2747050c2c620dc862c77b8f242551a8" },
"nvim-treesitter-context": { "branch": "master", "commit": "64dd4cf3f6fd0ab17622c5ce15c91fc539c3f24a" },
"nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" },
"nvim-web-devicons": { "branch": "master", "commit": "6788013bb9cb784e606ada44206b0e755e4323d7" },
"oil.nvim": { "branch": "master", "commit": "81b8a91735ad5cd24a6b3137f14a89f19176364f" },
"nvim-web-devicons": { "branch": "master", "commit": "803353450c374192393f5387b6a0176d0972b848" },
"oil.nvim": { "branch": "master", "commit": "f55b25e493a7df76371cfadd0ded5004cb9cd48a" },
"plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
"render-markdown.nvim": { "branch": "main", "commit": "da6a7b25471ab23824f3429225973186eb0b62d2" },
"render-markdown.nvim": { "branch": "main", "commit": "c54380dd4d8d1738b9691a7c349ecad7967ac12e" },
"supermaven-nvim": { "branch": "main", "commit": "07d20fce48a5629686aefb0a7cd4b25e33947d50" },
"telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" },
"telescope.nvim": { "branch": "master", "commit": "3333a52ff548ba0a68af6d8da1e54f9cd96e9179" },
"telescope.nvim": { "branch": "master", "commit": "0d8b6eaa0b5ae6bb3d9785f7a3ba4a4c6c1b1af2" },
"transparent.nvim": { "branch": "main", "commit": "8ac59883de84e9cd1850ea25cf087031c5ba7d54" },
"trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" },
"typescript-tools.nvim": { "branch": "master", "commit": "c2f5910074103705661e9651aa841e0d7eea9932" },
"vague.nvim": { "branch": "main", "commit": "fcc283576764474ccfbbcca240797d5d7f4d8a78" },
"vim-bujo": { "branch": "master", "commit": "ee3fecb5b3206b8073ac3fe4153391f320c99197" },

View file

@ -14,72 +14,110 @@
-- Angular requires a node_modules directory to probe for @angular/language-service and typescript
-- in order to use your projects configured versions.
local root_dir = vim.fn.getcwd()
local node_modules_dir = vim.fs.find('node_modules', { path = root_dir, upward = true })[1]
local project_root = node_modules_dir and vim.fs.dirname(node_modules_dir) or '?'
local fs, fn, uv = vim.fs, vim.fn, vim.uv
local function get_probe_dir()
return project_root and (project_root .. '/node_modules') or ''
--- Recursively solve for the original ngserver path on Windows
-- For a given ngserver path:
-- - If it is not a CMD wrapper, return the path;
-- - Or else, extract the path from the CMD wrapper.
--
-- @param cmd_path (string) path for the ngserver executable or its CMD wrapper.
-- @return (string) the original executable path for ngserver
-- @usage
-- -- Base case: cmd_path already points to ngserver (expected behavior on Linux)
-- resolve_cmd_shim('/home/user/project/node_modules/@angular/language-server/bin/ngserver')
-- => '/home/user/project/node_modules/@angular/language-server/bin/ngserver'
--
-- -- Recursive case: cmd_path points to a CMD wrapper (Windows)
-- resolve_cmd_shim('C:/Users/user/project/node_modules/.bin/ngserver.cmd')
-- => 'C:/Users/user/project/node_modules/@angular/language-server/bin/ngserver'
local function resolve_cmd_shim(cmd_path)
if not cmd_path:lower():match('%ngserver.cmd$') then
return cmd_path
end
local ok, content = pcall(fn.readblob, cmd_path)
if not ok or not content then
return cmd_path
end
local target = content:match('%s%"%%dp0%%\\([^\r\n]-ngserver[^\r\n]-)%"')
if not target then
return cmd_path
end
local full = fs.normalize(fs.joinpath(fs.dirname(cmd_path), target))
return resolve_cmd_shim(full)
end
local function get_angular_core_version()
if not project_root then
return ''
local function collect_node_modules(root_dir)
local results = {}
local project_node = fs.joinpath(root_dir, 'node_modules')
if uv.fs_stat(project_node) then
table.insert(results, project_node)
end
local package_json = project_root .. '/package.json'
if not vim.uv.fs_stat(package_json) then
return ''
local ngserver_exe = fn.exepath('ngserver')
if ngserver_exe and #ngserver_exe > 0 then
local realpath = uv.fs_realpath(ngserver_exe) or ngserver_exe
realpath = resolve_cmd_shim(realpath)
local candidate = fs.normalize(fs.joinpath(fs.dirname(realpath), '../../..'))
if uv.fs_stat(candidate) then
table.insert(results, candidate)
end
end
local contents = io.open(package_json):read '*a'
local json = vim.json.decode(contents)
if not json.dependencies then
return ''
end
local angular_core_version = json.dependencies['@angular/core']
angular_core_version = angular_core_version and angular_core_version:match('%d+%.%d+%.%d+')
return angular_core_version
return results
end
local default_probe_dir = get_probe_dir()
local default_angular_core_version = get_angular_core_version()
local function get_angular_core_version(root_dir)
local package_json = fs.joinpath(root_dir, 'package.json')
if not uv.fs_stat(package_json) then
return ''
end
-- structure should be like
-- - $EXTENSION_PATH
-- - @angular
-- - language-server
-- - bin
-- - ngserver
-- - typescript
local ngserver_exe = vim.fn.exepath('ngserver')
local ngserver_path = #(ngserver_exe or '') > 0 and vim.fs.dirname(vim.uv.fs_realpath(ngserver_exe)) or '?'
local extension_path = vim.fs.normalize(vim.fs.joinpath(ngserver_path, '../../../'))
local ok, content = pcall(fn.readblob, package_json)
if not ok or not content then
return ''
end
-- angularls will get module by `require.resolve(PROBE_PATH, MODULE_NAME)` of nodejs
local ts_probe_dirs = vim.iter({ extension_path, default_probe_dir }):join(',')
local ng_probe_dirs = vim
.iter({ extension_path, default_probe_dir })
:map(function(p)
return vim.fs.joinpath(p, '/@angular/language-server/node_modules')
end)
:join(',')
local json = vim.json.decode(content) or {}
local version = (json.dependencies or {})['@angular/core'] or ''
return version:match('%d+%.%d+%.%d+') or ''
end
---@type vim.lsp.Config
return {
cmd = {
'ngserver',
'--stdio',
'--tsProbeLocations',
ts_probe_dirs,
'--ngProbeLocations',
ng_probe_dirs,
'--angularCoreVersion',
default_angular_core_version,
},
cmd = function(dispatchers, config)
local root_dir = (config and config.root_dir) or fn.getcwd()
local node_paths = collect_node_modules(root_dir)
local ts_probe = table.concat(node_paths, ',')
local ng_probe = table.concat(
vim
.iter(node_paths)
:map(function(p)
return fs.joinpath(p, '@angular/language-server/node_modules')
end)
:totable(),
','
)
local cmd = {
'ngserver',
'--stdio',
'--tsProbeLocations',
ts_probe,
'--ngProbeLocations',
ng_probe,
'--angularCoreVersion',
get_angular_core_version(root_dir),
}
return vim.lsp.rpc.start(cmd, dispatchers)
end,
filetypes = { 'typescript', 'html', 'typescriptreact', 'typescript.tsx', 'htmlangular' },
root_markers = { 'angular.json', 'nx.json' },
}

View file

@ -36,6 +36,7 @@
---@type vim.lsp.Config
return {
cmd = function(dispatchers, config)
---@diagnostic disable: undefined-field
local local_cmd = {
vim.env.JAVA_HOME and (vim.env.JAVA_HOME .. '/bin/java') or 'java',
'-cp',
@ -48,6 +49,7 @@ return {
if config.apex_jvm_max_heap then
table.insert(local_cmd, '-Xmx' .. config.apex_jvm_max_heap)
end
---@diagnostic enable: undefined-field
table.insert(local_cmd, 'apex.jorje.lsp.ApexLanguageServerLauncher')
return vim.lsp.rpc.start(local_cmd, dispatchers)

View file

@ -82,9 +82,11 @@ return {
},
capabilities = {
textDocument = {
---@diagnostic disable-next-line: assign-type-mismatch
semanticTokens = vim.NIL,
},
workspace = {
---@diagnostic disable-next-line: assign-type-mismatch
semanticTokens = vim.NIL,
},
},

View file

@ -17,23 +17,32 @@ return {
return client.config.cmd_cwd == config.cmd_cwd
end,
filetypes = { -- https://ast-grep.github.io/reference/languages.html
'bash',
'c',
'cpp',
'rust',
'cs',
'css',
'elixir',
'go',
'haskell',
'html',
'java',
'python',
'javascript',
'javascriptreact',
'javascript.jsx',
'json',
'kotlin',
'lua',
'nix',
'php',
'python',
'ruby',
'rust',
'scala',
'solidity',
'swift',
'typescript',
'typescriptreact',
'typescript.tsx',
'html',
'css',
'kotlin',
'dart',
'lua',
'yaml',
},
root_markers = { 'sgconfig.yaml', 'sgconfig.yml' },
}

View file

@ -16,6 +16,7 @@ return {
cmd = { 'autohotkey_lsp', '--stdio' },
filetypes = { 'autohotkey' },
root_markers = { 'package.json' },
---@diagnostic disable-next-line: missing-fields
flags = { debounce_text_changes = 500 },
--capabilities = capabilities,
--on_attach = custom_attach,

View file

@ -12,6 +12,7 @@ local function set_python_path(command)
}
for _, client in ipairs(clients) do
if client.settings then
---@diagnostic disable-next-line: param-type-mismatch
client.settings.python = vim.tbl_deep_extend('force', client.settings.python or {}, { pythonPath = path })
else
client.config.settings = vim.tbl_deep_extend('force', client.config.settings, { python = { pythonPath = path } })
@ -25,20 +26,23 @@ return {
cmd = { 'basedpyright-langserver', '--stdio' },
filetypes = { 'python' },
root_markers = {
'pyrightconfig.json',
'pyproject.toml',
'setup.py',
'setup.cfg',
'requirements.txt',
'Pipfile',
'pyrightconfig.json',
'.git',
},
settings = {
basedpyright = {
analysis = {
autoSearchPaths = true,
useLibraryCodeForTypes = true,
diagnosticMode = 'openFilesOnly',
-- https://docs.basedpyright.com/latest/configuration/language-server-settings/
-- Explicitly setting `basedpyright.analysis.useLibraryCodeForTypes` is **discouraged** by the official docs.
-- Because it will override per-project configurations like `pyproject.toml`.
-- If left unset, its default value is `true`, and it can be correctly overridden by project config files.
},
},
},
@ -52,6 +56,7 @@ return {
-- Using client.request() directly because "basedpyright.organizeimports" is private
-- (not advertised via capabilities), which client:exec_cmd() refuses to call.
-- https://github.com/neovim/neovim/blob/c333d64663d3b6e0dd9aa440e433d346af4a3d81/runtime/lua/vim/lsp/client.lua#L1024-L1030
---@diagnostic disable-next-line: param-type-mismatch
client.request('workspace/executeCommand', params, nil, bufnr)
end, {
desc = 'Organize Imports',

View file

@ -34,7 +34,6 @@ return {
'jsonc',
'svelte',
'typescript',
'typescript.tsx',
'typescriptreact',
'vue',
},
@ -44,10 +43,18 @@ return {
-- As stated in the documentation above, this LSP supports monorepos and simple projects.
-- We select then from the project root, which is identified by the presence of a package
-- manager lock file.
local root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb', 'bun.lock' }
local root_markers = {
'package-lock.json',
'yarn.lock',
'pnpm-lock.yaml',
'bun.lockb',
'bun.lock',
'deno.lock',
}
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()
@ -55,7 +62,7 @@ return {
-- in its directory tree.
local filename = vim.api.nvim_buf_get_name(bufnr)
local biome_config_files = { 'biome.json', 'biome.jsonc' }
biome_config_files = util.insert_package_json(biome_config_files, 'biome', filename)
biome_config_files = util.insert_package_json(biome_config_files, 'biomejs', filename)
local is_buffer_using_biome = vim.fs.find(biome_config_files, {
path = filename,
type = 'file',

View file

@ -1,6 +1,13 @@
---@brief
---
--- 🛠️ bitbake language server
--- https://github.com/Freed-Wu/bitbake-language-server
---
--- `bitbake-language-server` can be installed via `pip`:
--- ```sh
--- pip install bitbake-language-server
--- ```
---
--- Language server for bitbake.
---@type vim.lsp.Config
return {

12
lsp/brioche.lua Normal file
View file

@ -0,0 +1,12 @@
---@brief
---
--- https://github.com/brioche-dev/brioche
---
--- `Brioche Language Server`.
---@type vim.lsp.Config
return {
cmd = { 'brioche', 'lsp' },
filetypes = { 'brioche' },
root_markers = { 'project.bri' },
}

View file

@ -1,13 +1,17 @@
--- @brief
--- https://github.com/bufbuild/buf
---
--- buf beta lsp included in the cli itself
--- buf lsp included in the cli itself
---
--- buf beta lsp is a Protobuf language server compatible with Buf modules and workspaces
--- buf lsp is a Protobuf language server compatible with Buf modules and workspaces
---@type vim.lsp.Config
return {
cmd = { 'buf', 'beta', 'lsp', '--timeout=0', '--log-format=text' },
cmd = { 'buf', 'lsp', 'serve', '--log-format=text' },
filetypes = { 'proto' },
root_markers = { 'buf.yaml', '.git' },
reuse_client = function(client, config)
-- `buf lsp serve` is meant to be used with multiple workspaces.
return client.name == config.name
end,
}

View file

@ -1,17 +0,0 @@
---@brief
---
--- https://github.com/bufbuild/buf-language-server
---
--- `buf-language-server` can be installed via `go install`:
--- ```sh
--- go install github.com/bufbuild/buf-language-server/cmd/bufls@latest
--- ```
---
--- bufls is a Protobuf language server compatible with Buf modules and workspaces
---@type vim.lsp.Config
return {
cmd = { 'bufls', 'serve' },
filetypes = { 'proto' },
root_markers = { 'buf.work.yaml', '.git' },
}

View file

@ -28,10 +28,12 @@ return {
'python',
'ruby',
'rust',
'swift',
'toml',
'text',
'typescript',
'typescriptreact',
'zig',
},
root_markers = { '.git', 'codebook.toml', '.codebook.toml' },
}

View file

@ -13,6 +13,33 @@
---
--- Please see [terms of use for GitHub Copilot](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot)
---
--- You need to enable `:help lsp-inline-completion` to receive suggestions. For example, you can enable it in the LspAttach event:
---
--- ```lua
--- vim.api.nvim_create_autocmd('LspAttach', {
--- callback = function(args)
--- local bufnr = args.buf
--- local client = assert(vim.lsp.get_client_by_id(args.data.client_id))
---
--- if client:supports_method(vim.lsp.protocol.Methods.textDocument_inlineCompletion, bufnr) then
--- vim.lsp.inline_completion.enable(true, { bufnr = bufnr })
---
--- vim.keymap.set(
--- 'i',
--- '<C-F>',
--- vim.lsp.inline_completion.get,
--- { desc = 'LSP: accept inline completion', buffer = bufnr }
--- )
--- vim.keymap.set(
--- 'i',
--- '<C-G>',
--- vim.lsp.inline_completion.select,
--- { desc = 'LSP: switch inline completion', buffer = bufnr }
--- )
--- end
--- end
--- })
--- ```
---@param bufnr integer,
---@param client vim.lsp.Client
@ -38,7 +65,7 @@ local function sign_in(bufnr, client)
if continue == 1 then
client:exec_cmd(command, { bufnr = bufnr }, function(cmd_err, cmd_result)
if cmd_err then
vim.notify(err.message, vim.log.levels.ERROR)
vim.notify(cmd_err.message, vim.log.levels.ERROR)
return
end
if cmd_result.status == 'OK' then

View file

@ -12,7 +12,15 @@ local util = require 'lspconfig.util'
---@type vim.lsp.Config
return {
cmd = { 'csharp-ls' },
cmd = function(dispatchers, config)
return vim.lsp.rpc.start({ 'csharp-ls' }, dispatchers, {
-- csharp-ls attempt to locate sln, slnx or csproj files from cwd, so set cwd to root directory.
-- If cmd_cwd is provided, use it instead.
cwd = config.cmd_cwd or config.root_dir,
env = config.cmd_env,
detached = config.detached,
})
end,
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(util.root_pattern '*.sln'(fname) or util.root_pattern '*.slnx'(fname) or util.root_pattern '*.csproj'(fname))
@ -21,4 +29,10 @@ return {
init_options = {
AutomaticWorkspaceInit = true,
},
get_language_id = function(_, ft)
if ft == 'cs' then
return 'csharp'
end
return ft
end,
}

View file

@ -14,7 +14,19 @@
return {
cmd = { 'css-variables-language-server', '--stdio' },
filetypes = { 'css', 'scss', 'less' },
root_markers = { 'package.json', '.git' },
-- Taken from lsp/ts_ls.lua to handle simple projects and monorepos.
root_dir = function(bufnr, on_dir)
local root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb', 'bun.lock' }
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has 'nvim-0.11.3' == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()
on_dir(project_root)
end,
-- Same as inlined defaults that don't seem to work without hardcoding them in the lua config
-- https://github.com/vunguyentuan/vscode-css-variables/blob/763a564df763f17aceb5f3d6070e0b444a2f47ff/packages/css-variables-language-server/src/CSSVariableManager.ts#L31-L50
settings = {

View file

@ -75,7 +75,24 @@ return {
'typescriptreact',
'typescript.tsx',
},
root_markers = { 'deno.json', 'deno.jsonc', '.git' },
root_dir = function(bufnr, on_dir)
-- The project root is where the LSP can be started from
local root_markers = { 'deno.lock' }
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- exclude non-deno projects (npm, yarn, pnpm, bun)
local non_deno_path = vim.fs.root(
bufnr,
{ 'package.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb', 'bun.lock' }
)
local project_root = vim.fs.root(bufnr, root_markers)
if non_deno_path and (not project_root or #non_deno_path >= #project_root) then
return
end
-- We fallback to the current working directory if no project root is found
on_dir(project_root or vim.fn.getcwd())
end,
settings = {
deno = {
enable = true,
@ -96,6 +113,7 @@ return {
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspDenolsCache', function()
client:exec_cmd({
title = 'DenolsCache',
command = 'deno.cache',
arguments = { {}, vim.uri_from_bufnr(bufnr) },
}, { bufnr = bufnr }, function(err, _, ctx)

12
lsp/djls.lua Normal file
View file

@ -0,0 +1,12 @@
---@brief
---
--- https://github.com/joshuadavidthomas/django-language-server
---
--- `djls`, a language server for the Django web framework.
---@type vim.lsp.Config
return {
cmd = { 'djls', 'serve' },
filetypes = { 'htmldjango', 'html', 'python' },
root_markers = { 'manage.py', 'pyproject.toml', '.git' },
}

View file

@ -23,6 +23,7 @@ end
local function ds_pinyin_lsp_off(bufnr)
local ds_pinyin_lsp_client = vim.lsp.get_clients({ bufnr = bufnr, name = 'ds_pinyin_lsp' })[1]
if ds_pinyin_lsp_client then
---@diagnostic disable-next-line: param-type-mismatch
ds_pinyin_lsp_client:notify('$/turn/completion', {
['completion_on'] = false,
})
@ -34,6 +35,7 @@ end
local function ds_pinyin_lsp_on(bufnr)
local ds_pinyin_lsp_client = vim.lsp.get_clients({ bufnr = bufnr, name = 'ds_pinyin_lsp' })[1]
if ds_pinyin_lsp_client then
---@diagnostic disable-next-line: param-type-mismatch
ds_pinyin_lsp_client:notify('$/turn/completion', {
['completion_on'] = true,
})

View file

@ -32,6 +32,7 @@
---@type vim.lsp.Config
return {
cmd = { 'elixir-ls' },
filetypes = { 'elixir', 'eelixir', 'heex', 'surface' },
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)

View file

@ -19,11 +19,9 @@ return {
'htmldjango',
'javascriptreact',
'less',
'pug',
'sass',
'scss',
'svelte',
'templ',
'typescriptreact',
'vue',
},

View file

@ -1,21 +0,0 @@
---@brief
---
--- https://erlang-ls.github.io
---
--- Language Server for Erlang.
---
--- Clone [erlang_ls](https://github.com/erlang-ls/erlang_ls)
--- Compile the project with `make` and copy resulting binaries somewhere in your $PATH eg. `cp _build/*/bin/* ~/local/bin`
---
--- Installation instruction can be found [here](https://github.com/erlang-ls/erlang_ls).
---
--- Installation requirements:
--- - [Erlang OTP 21+](https://github.com/erlang/otp)
--- - [rebar3 3.9.1+](https://github.com/erlang/rebar3)
---@type vim.lsp.Config
return {
cmd = { 'erlang_ls' },
filetypes = { 'erlang' },
root_markers = { 'rebar.config', 'erlang.mk', '.git' },
}

View file

@ -74,7 +74,7 @@ return {
},
workspace_required = true,
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(0, 'LspEslintFixAll', function()
vim.api.nvim_buf_create_user_command(bufnr, 'LspEslintFixAll', function()
client:request_sync('workspace/executeCommand', {
command = 'eslint.applyAllFixes',
arguments = {
@ -95,6 +95,12 @@ return {
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- exclude deno
if vim.fs.root(bufnr, { 'deno.json', 'deno.jsonc', 'deno.lock' }) then
return
end
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()
@ -122,6 +128,7 @@ return {
-- Refer to https://github.com/Microsoft/vscode-eslint#settings-options for documentation.
settings = {
validate = 'on',
---@diagnostic disable-next-line: assign-type-mismatch
packageManager = nil,
useESLintClass = false,
experimental = {
@ -194,9 +201,8 @@ return {
-- Support Yarn2 (PnP) projects
local pnp_cjs = root_dir .. '/.pnp.cjs'
local pnp_js = root_dir .. '/.pnp.js'
if vim.uv.fs_stat(pnp_cjs) or vim.uv.fs_stat(pnp_js) then
local cmd = config.cmd
config.cmd = vim.list_extend({ 'yarn', 'exec' }, cmd)
if type(config.cmd) == 'table' and (vim.uv.fs_stat(pnp_cjs) or vim.uv.fs_stat(pnp_js)) then
config.cmd = vim.list_extend({ 'yarn', 'exec' }, config.cmd --[[@as table]])
end
end
end,

View file

@ -12,7 +12,7 @@
---@type vim.lsp.Config
return {
filetypes = { 'elixir', 'eelixir', 'heex', 'surface' },
cmd = { 'expert' },
cmd = { 'expert', '--stdio' },
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
--- Elixir workspaces may have multiple `mix.exs` files, for an "umbrella" layout or monorepo.

View file

@ -14,7 +14,16 @@
---@type vim.lsp.Config
return {
cmd = { 'npx', '--no-install', 'flow', 'lsp' },
cmd = function(dispatchers)
local cmd = nil
if vim.fn.executable('flow') then
cmd = { 'flow', 'lsp' }
else
cmd = { 'npx', '--no-install', 'flow', 'lsp' }
end
return vim.lsp.rpc.start(cmd, dispatchers)
end,
filetypes = { 'javascript', 'javascriptreact', 'javascript.jsx' },
root_markers = { '.flowconfig' },
}

448
lsp/gitlab_duo.lua Normal file
View file

@ -0,0 +1,448 @@
---@brief
---
--- GitLab Duo Language Server Configuration for Neovim
---
--- https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp
---
--- The GitLab LSP enables any editor or IDE to integrate with GitLab Duo
--- for AI-powered code suggestions via the Language Server Protocol.
---
--- Prerequisites:
--- - Node.js and npm installed
--- - GitLab account with Duo Pro license
--- - Internet connection for OAuth device flow
---
--- Setup:
--- 1. Run :LspGitLabDuoSignIn to start OAuth authentication
--- 2. Follow the browser prompts to authorize
--- 3. Enable inline completion in LspAttach event (see example below)
---
--- Inline Completion Example:
--- ```lua
--- vim.api.nvim_create_autocmd('LspAttach', {
--- callback = function(args)
--- local bufnr = args.buf
--- local client = assert(vim.lsp.get_client_by_id(args.data.client_id))
---
--- if vim.lsp.inline_completion and
--- client:supports_method(vim.lsp.protocol.Methods.textDocument_inlineCompletion, bufnr) then
--- vim.lsp.inline_completion.enable(true, { bufnr = bufnr })
---
--- -- Tab to accept suggestion
--- vim.keymap.set('i', '<Tab>', function()
--- if vim.lsp.inline_completion.is_visible() then
--- return vim.lsp.inline_completion.accept()
--- else
--- return '<Tab>'
--- end
--- end, { expr = true, buffer = bufnr, desc = 'GitLab Duo: Accept suggestion' })
---
--- -- Alt/Option+[ for previous suggestion
--- vim.keymap.set('i', '<M-[>', vim.lsp.inline_completion.select_prev,
--- { buffer = bufnr, desc = 'GitLab Duo: Previous suggestion' })
---
--- -- Alt/Option+] for next suggestion
--- vim.keymap.set('i', '<M-]>', vim.lsp.inline_completion.select_next,
--- { buffer = bufnr, desc = 'GitLab Duo: Next suggestion' })
--- end
--- end
--- })
--- ```
-- Configuration
local config = {
gitlab_url = 'https://gitlab.com',
-- This is a oauth application created from tachyons-gitlab account with `api` scope
client_id = '00bb391f527d2e77b3467b0b6b900151cc6a28dcfb18fa1249871e43bc3e5832',
scopes = 'api',
token_file = vim.fn.stdpath('data') .. '/gitlab_duo_oauth.json',
}
-- Helper function to make POST requests with curl via vim.system
local function curl_post(url, data, headers)
local curl_args = {
'curl',
'-s',
'-w',
'\n%{http_code}',
'-X',
'POST',
url,
}
-- Add headers
for key, value in pairs(headers or {}) do
table.insert(curl_args, '-H')
table.insert(curl_args, key .. ': ' .. value)
end
-- Add data
if data then
table.insert(curl_args, '-d')
table.insert(curl_args, data)
end
local result = vim.system(curl_args, { text = true }):wait()
-- Split body and status code
local output = result.stdout or ''
local body_end = output:match('.*\n()%d+$')
local body = ''
local status = 0
if body_end then
body = output:sub(1, body_end - 2) -- -2 to remove trailing newline
status = tonumber(output:match('\n(%d+)$')) or 0
else
body = output
end
return {
status = status,
body = body,
}
end
-- Token management
local function save_token(token_data)
token_data.saved_at = os.time()
local file = io.open(config.token_file, 'w')
if file then
file:write(vim.json.encode(token_data))
file:close()
return true
end
return false
end
local function load_token()
if vim.fn.filereadable(config.token_file) == 0 then
return nil
end
local blob = vim.fn.readblob(config.token_file)
return vim.json.decode(blob)
end
local function is_token_expired(token_data)
if not token_data or not token_data.saved_at or not token_data.expires_in then
return true
end
local token_age = os.time() - token_data.saved_at
return token_age >= (token_data.expires_in - 60) -- 60 second buffer
end
local function refresh_access_token(refresh_token)
vim.notify('Refreshing GitLab OAuth token...', vim.log.levels.INFO)
local response = curl_post(
config.gitlab_url .. '/oauth/token',
string.format('client_id=%s&refresh_token=%s&grant_type=refresh_token', config.client_id, refresh_token),
{ ['Content-Type'] = 'application/x-www-form-urlencoded' }
)
if response.status ~= 200 then
vim.notify('Failed to refresh token: ' .. (response.body or 'Unknown error'), vim.log.levels.ERROR)
return nil
end
local ok, body = pcall(vim.json.decode, response.body)
if not ok or not body.access_token then
vim.notify('Invalid refresh response', vim.log.levels.ERROR)
return nil
end
save_token(body)
vim.notify('Token refreshed successfully', vim.log.levels.INFO)
return body
end
local function get_valid_token()
local token_data = load_token()
if not token_data then
return nil, 'no_token'
end
if is_token_expired(token_data) then
if token_data.refresh_token then
local new_token_data = refresh_access_token(token_data.refresh_token)
if new_token_data then
return new_token_data.access_token, 'refreshed'
end
return nil, 'refresh_failed'
end
return nil, 'expired'
end
return token_data.access_token, 'valid'
end
-- OAuth Device Flow
local function device_authorization()
local response = curl_post(
config.gitlab_url .. '/oauth/authorize_device',
string.format('client_id=%s&scope=%s', config.client_id, config.scopes),
{ ['Content-Type'] = 'application/x-www-form-urlencoded' }
)
if response.status ~= 200 then
vim.notify('Device authorization failed: ' .. response.status, vim.log.levels.ERROR)
return nil
end
local data = vim.json.decode(response.body)
return data
end
local function poll_for_token(device_code, interval, client)
local max_attempts = 60
local attempts = 0
local function poll()
attempts = attempts + 1
local response = curl_post(
config.gitlab_url .. '/oauth/token',
string.format(
'client_id=%s&device_code=%s&grant_type=urn:ietf:params:oauth:grant-type:device_code',
config.client_id,
device_code
),
{ ['Content-Type'] = 'application/x-www-form-urlencoded' }
)
local ok, body = pcall(vim.json.decode, response.body)
if not ok then
vim.notify('Failed to parse token response', vim.log.levels.ERROR)
return
end
if response.status == 200 and body.access_token then
save_token(body)
vim.notify('GitLab Duo authentication successful!', vim.log.levels.INFO)
-- Update LSP with new token
vim.schedule(function()
client:notify('workspace/didChangeConfiguration', {
settings = {
token = body.access_token,
baseUrl = config.gitlab_url,
},
})
end)
return
end
if body.error == 'authorization_pending' then
if attempts < max_attempts then
vim.defer_fn(poll, interval * 1000)
else
vim.notify('Authorization timed out', vim.log.levels.ERROR)
end
elseif body.error == 'slow_down' then
vim.defer_fn(poll, (interval + 5) * 1000)
elseif body.error == 'access_denied' then
vim.notify('Authorization denied', vim.log.levels.ERROR)
elseif body.error == 'expired_token' then
vim.notify('Device code expired. Please run :LspGitLabDuoSignIn again', vim.log.levels.ERROR)
else
vim.notify('OAuth error: ' .. (body.error or 'unknown'), vim.log.levels.ERROR)
end
end
poll()
end
---@param client vim.lsp.Client
local function sign_in(client)
vim.notify('Starting GitLab device authorization...', vim.log.levels.INFO)
local auth_data = device_authorization()
if not auth_data then
return
end
vim.ui.open(auth_data.verification_uri .. '?user_code=' .. auth_data.user_code)
poll_for_token(auth_data.device_code, auth_data.interval or 5, client)
end
---@param client vim.lsp.Client
local function sign_out(client)
local ok = os.remove(config.token_file)
if ok then
vim.notify('Signed out. Token removed.', vim.log.levels.INFO)
client:notify('workspace/didChangeConfiguration', {
settings = { token = '' },
})
else
vim.notify('Failed to remove token file', vim.log.levels.ERROR)
end
end
local function show_status()
local token_data = load_token()
if not token_data then
vim.notify('Not signed in. Run :LspGitLabDuoSignIn to authenticate.', vim.log.levels.INFO)
return
end
local info = {
'GitLab Duo Status:',
'',
'Instance: ' .. config.gitlab_url,
'Signed in: Yes',
'Has refresh token: ' .. (token_data.refresh_token and 'Yes' or 'No'),
}
if token_data.saved_at and token_data.expires_in then
local time_left = token_data.expires_in - (os.time() - token_data.saved_at)
if time_left > 0 then
local hours = math.floor(time_left / 3600)
local minutes = math.floor((time_left % 3600) / 60)
table.insert(info, string.format('Token expires in: %dh %dm', hours, minutes))
else
table.insert(info, 'Token status: EXPIRED')
end
end
vim.notify(table.concat(info, '\n'), vim.log.levels.INFO)
end
---@type vim.lsp.Config
return {
cmd = {
'npx',
'--registry=https://gitlab.com/api/v4/packages/npm/',
'@gitlab-org/gitlab-lsp',
'--stdio',
},
root_markers = { '.git' },
filetypes = {
'ruby',
'go',
'javascript',
'typescript',
'typescriptreact',
'javascriptreact',
'rust',
'lua',
'python',
'java',
'cpp',
'c',
'php',
'cs',
'kotlin',
'swift',
'scala',
'vue',
'svelte',
'html',
'css',
'scss',
'json',
'yaml',
},
init_options = {
editorInfo = {
name = 'Neovim',
version = tostring(vim.version()),
},
editorPluginInfo = {
name = 'Neovim LSP',
version = tostring(vim.version()),
},
ide = {
name = 'Neovim',
version = tostring(vim.version()),
vendor = 'Neovim',
},
extension = {
name = 'Neovim LSP Client',
version = tostring(vim.version()),
},
},
settings = {
baseUrl = config.gitlab_url,
logLevel = 'info',
codeCompletion = {
enableSecretRedaction = true,
},
telemetry = {
enabled = false,
},
featureFlags = {
streamCodeGenerations = false,
},
},
on_init = function(client)
-- Handle token validation errors
client.handlers['$/gitlab/token/check'] = function(_, result)
if result and result.reason then
vim.notify(string.format('GitLab Duo: %s - %s', result.reason, result.message or ''), vim.log.levels.ERROR)
-- Try to refresh if possible
local token_data = load_token()
if token_data and token_data.refresh_token then
vim.schedule(function()
local new_token_data = refresh_access_token(token_data.refresh_token)
if new_token_data then
client:notify('workspace/didChangeConfiguration', {
settings = { token = new_token_data.access_token, baseUrl = config.gitlab_url },
})
else
vim.notify('Run :LspGitLabDuoSignIn to re-authenticate', vim.log.levels.WARN)
end
end)
else
vim.notify('Run :LspGitLabDuoSignIn to authenticate', vim.log.levels.WARN)
end
end
end
-- Handle feature state changes
client.handlers['$/gitlab/featureStateChange'] = function(_, result)
if result and result.state == 'disabled' and result.checks then
for _, check in ipairs(result.checks) do
vim.notify(string.format('GitLab Duo: %s', check.message or check.id), vim.log.levels.WARN)
end
end
end
-- Check authentication status
local token, status = get_valid_token()
if token then
client:notify('workspace/didChangeConfiguration', {
settings = {
token = token,
baseUrl = config.gitlab_url,
},
})
end
if not token then
vim.notify('GitLab Duo: Not authenticated. Run :LspGitLabDuoSignIn to sign in.', vim.log.levels.WARN)
elseif status == 'refreshed' then
vim.notify('GitLab Duo: Token refreshed automatically', vim.log.levels.INFO)
end
end,
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspGitLabDuoSignIn', function()
sign_in(client)
end, { desc = 'Sign in to GitLab Duo with OAuth' })
vim.api.nvim_buf_create_user_command(bufnr, 'LspGitLabDuoSignOut', function()
sign_out(client)
end, { desc = 'Sign out from GitLab Duo' })
vim.api.nvim_buf_create_user_command(bufnr, 'LspGitLabDuoStatus', function()
show_status()
end, { desc = 'Show GitLab Duo authentication status' })
end,
}

View file

@ -25,6 +25,7 @@
---@type vim.lsp.Config
return {
cmd = function(dispatchers, config)
---@diagnostic disable-next-line: undefined-field
local cmd = (config.init_options.glint.useGlobal or not config.root_dir) and { 'glint-language-server' }
or { config.root_dir .. '/node_modules/.bin/glint-language-server' }
return vim.lsp.rpc.start(cmd, dispatchers)

View file

@ -0,0 +1,13 @@
---@brief
---
--- https://github.com/google/gn-language-server
---
--- A language server for GN, the build configuration language used in Chromium,
--- Fuchsia, and other projects.
---@type vim.lsp.Config
return {
cmd = { 'gn-language-server', '--stdio' },
filetypes = { 'gn' },
root_markers = { '.gn', '.git' },
}

View file

@ -18,7 +18,22 @@ return {
cmd = { 'golangci-lint-langserver' },
filetypes = { 'go', 'gomod' },
init_options = {
command = { 'golangci-lint', 'run', '--output.json.path=stdout', '--show-stats=false' },
command = {
'golangci-lint',
'run',
-- disable all output formats that might be enabled by the users .golangci.yml
'--output.text.path=',
'--output.tab.path=',
'--output.html.path=',
'--output.checkstyle.path=',
'--output.junit-xml.path=',
'--output.teamcity.path=',
'--output.sarif.path=',
-- disable stats output
'--show-stats=false',
-- enable JSON output to be used by the language server
'--output.json.path=stdout',
},
},
root_markers = {
'.golangci.yml',

View file

@ -21,6 +21,7 @@
return {
cmd = { 'harper-ls', '--stdio' },
filetypes = {
'asciidoc',
'c',
'cpp',
'cs',
@ -47,5 +48,5 @@ return {
'clojure',
'sh',
},
root_markers = { '.git' },
root_markers = { '.harper-dictionary.txt', '.git' },
}

View file

@ -25,7 +25,7 @@ return {
settings = {
haskell = {
formattingProvider = 'ormolu',
cabalFormattingProvider = 'cabalfmt',
cabalFormattingProvider = 'cabal-fmt',
},
},
}

18
lsp/home_assistant.lua Normal file
View file

@ -0,0 +1,18 @@
---@brief
---
--- https://github.com/keesschollaart81/vscode-home-assistant
---
--- `vscode-home-assistant` can be installed via from source or by downloading
--- and extracting the VSCode "Home Assistant Config Helper" extension
---
--- `vscode-home-assistant` is a language server for Home Assistant ported from the VSCode "Home Assistant Config Helper" extension.
---@type vim.lsp.Config
return {
cmd = { 'vscode-home-assistant', '--stdio' },
filetypes = { 'yaml' },
root_markers = {
'configuration.yaml',
'configuration.yml',
},
}

View file

@ -25,7 +25,7 @@
---@type vim.lsp.Config
return {
cmd = { 'vscode-html-language-server', '--stdio' },
filetypes = { 'html', 'templ' },
filetypes = { 'html' },
root_markers = { 'package.json', '.git' },
settings = {},
init_options = {

13
lsp/hylo_ls.lua Normal file
View file

@ -0,0 +1,13 @@
---@brief
---
--- https://github.com/hylo-lang/hylo-language-server
---
--- A language server for the Hylo programming language.
---@type vim.lsp.Config
return {
cmd = { 'hylo-language-server', '--stdio' },
filetypes = { 'hylo' },
root_markers = { '.git' },
settings = {},
}

View file

@ -30,4 +30,11 @@ return {
cmd = { 'intelephense', '--stdio' },
filetypes = { 'php' },
root_markers = { '.git', 'composer.json' },
settings = {
intelephense = {
telemetry = {
enabled = false,
},
},
},
}

View file

@ -8,6 +8,7 @@
---@type vim.lsp.Config
return {
cmd = { 'java-language-server' },
filetypes = { 'java' },
root_markers = { 'build.gradle', 'build.gradle.kts', 'pom.xml', '.git' },
settings = {},

View file

@ -32,22 +32,8 @@
--- vim.lsp.config('jdtls', { cmd = { 'jdtls' } })
--- ```
local env = {
HOME = vim.uv.os_homedir(),
XDG_CACHE_HOME = os.getenv 'XDG_CACHE_HOME',
JDTLS_JVM_ARGS = os.getenv 'JDTLS_JVM_ARGS',
}
local function get_cache_dir()
return env.XDG_CACHE_HOME and env.XDG_CACHE_HOME or env.HOME .. '/.cache'
end
local function get_jdtls_cache_dir()
return get_cache_dir() .. '/jdtls'
end
local function get_jdtls_config_dir()
return get_jdtls_cache_dir() .. '/config'
return vim.fn.stdpath('cache') .. '/jdtls'
end
local function get_jdtls_workspace_dir()
@ -55,39 +41,62 @@ local function get_jdtls_workspace_dir()
end
local function get_jdtls_jvm_args()
local env = os.getenv('JDTLS_JVM_ARGS')
local args = {}
for a in string.gmatch((env.JDTLS_JVM_ARGS or ''), '%S+') do
for a in string.gmatch((env or ''), '%S+') do
local arg = string.format('--jvm-arg=%s', a)
table.insert(args, arg)
end
return unpack(args)
end
local root_markers1 = {
-- Multi-module projects
'mvnw', -- Maven
'gradlew', -- Gradle
'settings.gradle', -- Gradle
'settings.gradle.kts', -- Gradle
-- Use git directory as last resort for multi-module maven projects
-- In multi-module maven projects it is not really possible to determine what is the parent directory
-- and what is submodule directory. And jdtls does not break if the parent directory is at higher level than
-- actual parent pom.xml so propagating all the way to root git directory is fine
'.git',
}
local root_markers2 = {
-- Single-module projects
'build.xml', -- Ant
'pom.xml', -- Maven
'build.gradle', -- Gradle
'build.gradle.kts', -- Gradle
}
---@type vim.lsp.Config
return {
cmd = {
'jdtls',
'-configuration',
get_jdtls_config_dir(),
'-data',
get_jdtls_workspace_dir(),
get_jdtls_jvm_args(),
},
---@param dispatchers? vim.lsp.rpc.Dispatchers
---@param config vim.lsp.ClientConfig
cmd = function(dispatchers, config)
local workspace_dir = get_jdtls_workspace_dir()
local data_dir = workspace_dir
if config.root_dir then
data_dir = data_dir .. '/' .. vim.fn.fnamemodify(config.root_dir, ':p:h:t')
end
local config_cmd = {
'jdtls',
'-data',
data_dir,
get_jdtls_jvm_args(),
}
return vim.lsp.rpc.start(config_cmd, dispatchers, {
cwd = config.cmd_cwd,
env = config.cmd_env,
detached = config.detached,
})
end,
filetypes = { 'java' },
root_markers = {
-- Multi-module projects
'.git',
'build.gradle',
'build.gradle.kts',
-- Single-module projects
'build.xml', -- Ant
'pom.xml', -- Maven
'settings.gradle', -- Gradle
'settings.gradle.kts', -- Gradle
},
init_options = {
workspace = get_jdtls_workspace_dir(),
jvm_args = {},
os_config = nil,
},
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers1, root_markers2 }
or vim.list_extend(root_markers1, root_markers2),
init_options = {},
}

View file

@ -2,12 +2,12 @@
---
--- https://github.com/julia-vscode/julia-vscode
---
--- LanguageServer.jl can be installed with `julia` and `Pkg`:
--- LanguageServer.jl, SymbolServer.jl and StaticLint.jl can be installed with `julia` and `Pkg`:
--- ```sh
--- julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.add("LanguageServer")'
--- julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.add("LanguageServer"); Pkg.add("SymbolServer"); Pkg.add("StaticLint")'
--- ```
--- where `~/.julia/environments/nvim-lspconfig` is the location where
--- the default configuration expects LanguageServer.jl to be installed.
--- the default configuration expects LanguageServer.jl, SymbolServer.jl and StaticLint.jl to be installed.
---
--- To update an existing install, use the following command:
--- ```sh
@ -36,6 +36,7 @@ local function activate_env(path)
local function _activate_env(environment)
if environment then
for _, julials_client in ipairs(julials_clients) do
---@diagnostic disable-next-line: param-type-mismatch
julials_client:notify('julia/activateenvironment', { envPath = environment })
end
vim.notify('Julia environment activated: \n`' .. environment .. '`', vim.log.levels.INFO)
@ -89,7 +90,7 @@ local cmd = {
"environments", "nvim-lspconfig"
)
pushfirst!(LOAD_PATH, ls_install_path)
using LanguageServer
using LanguageServer, SymbolServer, StaticLint
popfirst!(LOAD_PATH)
depot_path = get(ENV, "JULIA_DEPOT_PATH", "")
project_path = let

View file

@ -37,6 +37,6 @@ return {
cmd = { 'kotlin-language-server' },
init_options = {
-- Enables caching and use project root to store cache data.
storagePath = vim.fs.root(vim.fn.expand '%:p:h', root_files),
storagePath = vim.fs.root(vim.fn.expand '%:p:h', root_files) --[[@as string]],
},
}

View file

@ -4,13 +4,12 @@
---
--- Lexical is a next-generation language server for the Elixir programming language.
---
--- Follow the [Detailed Installation Instructions](https://github.com/lexical-lsp/lexical/blob/main/pages/installation.md)
---
--- **By default, `lexical` doesn't have a `cmd` set.**
--- This is because nvim-lspconfig does not make assumptions about your path.
--- To install from source, follow the [Detailed Installation Instructions](https://github.com/lexical-lsp/lexical/blob/main/pages/installation.md).
--- Ensure to point `cmd` to the generated `_build/dev/package/lexical/start_lexical.sh` executable.
---@type vim.lsp.Config
return {
cmd = { 'lexical' },
filetypes = { 'elixir', 'eelixir', 'heex', 'surface' },
root_markers = { 'mix.exs', '.git' },
}

View file

@ -36,6 +36,7 @@ local language_id_mapping = {
return {
cmd = { 'ltex-ls-plus' },
filetypes = {
'asciidoc',
'bib',
'context',
'gitcommit',
@ -62,6 +63,7 @@ return {
settings = {
ltex = {
enabled = {
'asciidoc',
'bib',
'context',
'gitcommit',

View file

@ -12,28 +12,29 @@
--- analysis, and location handling for plugins on runtime path, you can use the following
--- settings.
---
vim.lsp.config('lua_ls', {
--- ```lua
vim.lsp.config("lua_ls", {
on_init = function(client)
if client.workspace_folders then
local path = client.workspace_folders[1].name
if
path ~= vim.fn.stdpath('config')
and (vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc'))
path ~= vim.fn.stdpath("config")
and (vim.uv.fs_stat(path .. "/.luarc.json") or vim.uv.fs_stat(path .. "/.luarc.jsonc"))
then
return
end
end
client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, {
client.config.settings.Lua = vim.tbl_deep_extend("force", client.config.settings.Lua, {
runtime = {
-- Tell the language server which version of Lua you're using (most
-- likely LuaJIT in the case of Neovim)
version = 'LuaJIT',
version = "LuaJIT",
-- Tell the language server how to find Lua modules same way as Neovim
-- (see `:h lua-module-load`)
path = {
'lua/?.lua',
'lua/?/init.lua',
"lua/?.lua",
"lua/?/init.lua",
},
},
-- Make the server aware of Neovim runtime files
@ -41,39 +42,54 @@ vim.lsp.config('lua_ls', {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME,
-- vim.fn.expand("~/.local/share/love2d/library"),
-- Depending on the usage, you might want to add additional paths
-- here.
-- '${3rd}/love2d/library'
-- '${3rd}/busted/library'
}
-- '${3rd}/luv/library',
-- '${3rd}/busted/library',
"${3rd}/love2d/library",
},
-- Or pull in all of 'runtimepath'.
-- NOTE: this is a lot slower and will cause issues when working on
-- your own configuration.
-- See https://github.com/neovim/nvim-lspconfig/issues/3189
-- library = {
-- vim.api.nvim_get_runtime_file('', true),
-- }
}
-- library = vim.api.nvim_get_runtime_file('', true),
},
})
end,
settings = {
Lua = {}
}
Lua = {},
},
})
--- ```
---
--- See `lua-language-server`'s [documentation](https://luals.github.io/wiki/settings/) for an explanation of the above fields:
--- * [Lua.runtime.path](https://luals.github.io/wiki/settings/#runtimepath)
--- * [Lua.workspace.library](https://luals.github.io/wiki/settings/#workspacelibrary)
---
local root_markers1 = {
".emmyrc.json",
".luarc.json",
".luarc.jsonc",
}
local root_markers2 = {
".luacheckrc",
".stylua.toml",
"stylua.toml",
"selene.toml",
"selene.yml",
}
---@type vim.lsp.Config
return {
cmd = { 'lua-language-server' },
filetypes = { 'lua' },
root_markers = {
'.luarc.json',
'.luarc.jsonc',
'.luacheckrc',
'.stylua.toml',
'stylua.toml',
'selene.toml',
'selene.yml',
'.git',
cmd = { "lua-language-server" },
filetypes = { "lua" },
root_markers = vim.fn.has("nvim-0.11.3") == 1 and { root_markers1, root_markers2, { ".git" } }
or vim.list_extend(vim.list_extend(root_markers1, root_markers2), { ".git" }),
settings = {
Lua = {
codeLens = { enable = true },
hint = { enable = true, semicolon = "Disable" },
},
},
}

View file

@ -1,6 +1,6 @@
---@brief
---
--- https://github.com/Decodetalkers/neocmakelsp
--- https://github.com/neocmakelsp/neocmakelsp
---
--- CMake LSP Implementation
---
@ -18,7 +18,7 @@
---@type vim.lsp.Config
return {
cmd = { 'neocmakelsp', '--stdio' },
cmd = { 'neocmakelsp', 'stdio' },
filetypes = { 'cmake' },
root_markers = { '.git', 'build', 'cmake' },
}

View file

@ -2,10 +2,11 @@
---
--- https://github.com/elixir-tools/next-ls
---
--- **By default, next-ls does not set its `cmd`. Please see the following [detailed instructions](https://www.elixir-tools.dev/docs/next-ls/installation/) for possible installation methods.**
--- **Please see the following [detailed instructions](https://www.elixir-tools.dev/docs/next-ls/installation/) for possible installation methods.**
---@type vim.lsp.Config
return {
cmd = { 'nextls', '--stdio' },
filetypes = { 'elixir', 'eelixir', 'heex', 'surface' },
root_markers = { 'mix.exs', '.git' },
}

View file

@ -1,20 +0,0 @@
---@brief
---
--- https://github.com/ocaml-lsp/ocaml-language-server
---
--- `ocaml-language-server` can be installed via `npm`
--- ```sh
--- npm install -g ocaml-language-server
--- ```
local util = require 'lspconfig.util'
---@type vim.lsp.Config
return {
cmd = { 'ocaml-language-server', '--stdio' },
filetypes = { 'ocaml', 'reason' },
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(util.root_pattern('*.opam', 'esy.json', 'package.json')(fname))
end,
}

View file

@ -9,7 +9,40 @@
--- opam install ocaml-lsp-server
--- ```
local util = require 'lspconfig.util'
-- https://github.com/ocaml/ocaml-lsp/blob/master/ocaml-lsp-server/docs/ocamllsp/switchImplIntf-spec.md
local function switch_impl_intf(bufnr, client)
local method_name = 'ocamllsp/switchImplIntf'
---@diagnostic disable-next-line:param-type-mismatch
if not client or not client:supports_method(method_name) then
return vim.notify(('method %s is not supported by any servers active on the current buffer'):format(method_name))
end
local uri = vim.lsp.util.make_given_range_params(nil, nil, bufnr, client.offset_encoding).textDocument.uri
if not uri then
return vim.notify('could not get URI for current buffer')
end
local params = { uri }
---@diagnostic disable-next-line:param-type-mismatch
client:request(method_name, params, function(err, result)
if err then
error(tostring(err))
end
if not result or #result == 0 then
vim.notify('corresponding file cannot be determined')
elseif #result == 1 then
vim.cmd.edit(vim.uri_to_fname(result[1]))
else
vim.ui.select(
result,
{ prompt = 'Select an implementation/interface:', format_item = vim.uri_to_fname },
function(choice)
if choice then
vim.cmd.edit(vim.uri_to_fname(choice))
end
end
)
end
end, bufnr)
end
local language_id_of = {
menhir = 'ocaml.menhir',
@ -20,17 +53,36 @@ local language_id_of = {
dune = 'dune',
}
local get_language_id = function(_, ftype)
return language_id_of[ftype]
local language_id_of_ext = {
mll = language_id_of.ocamllex,
mly = language_id_of.menhir,
mli = language_id_of.ocamlinterface,
}
local get_language_id = function(bufnr, ftype)
if ftype == 'ocaml' then
local path = vim.api.nvim_buf_get_name(bufnr)
local ext = vim.fn.fnamemodify(path, ':e')
return language_id_of_ext[ext] or language_id_of.ocaml
else
return language_id_of[ftype]
end
end
local root_markers1 = { 'dune-project', 'dune-workspace' }
local root_markers2 = { '*.opam', 'opam', 'esy.json', 'package.json' }
local root_markers3 = { '.git' }
---@type vim.lsp.Config
return {
cmd = { 'ocamllsp' },
filetypes = { 'ocaml', 'menhir', 'ocamlinterface', 'ocamllex', 'reason', 'dune' },
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(util.root_pattern('*.opam', 'esy.json', 'package.json', '.git', 'dune-project', 'dune-workspace')(fname))
end,
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers1, root_markers2, root_markers3 }
or vim.list_extend(vim.list_extend(root_markers1, root_markers2), root_markers3),
get_language_id = get_language_id,
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspOcamllspSwitchImplIntf', function()
switch_impl_intf(bufnr, client)
end, { desc = 'Switch between implementation/interface' })
end,
}

View file

@ -8,8 +8,6 @@
---
--- OmniSharp requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed.
---
--- **By default, omnisharp-roslyn doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary.
---
--- For `go_to_definition` to work fully, extended `textDocument/definition` handler is needed, for example see [omnisharp-extended-lsp.nvim](https://github.com/Hoffs/omnisharp-extended-lsp.nvim)
---
---
@ -32,7 +30,8 @@ return {
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(
util.root_pattern '*.sln'(fname)
util.root_pattern '*.slnx'(fname)
or util.root_pattern '*.sln'(fname)
or util.root_pattern '*.csproj'(fname)
or util.root_pattern 'omnisharp.json'(fname)
or util.root_pattern 'function.json'(fname)

32
lsp/oso.lua Normal file
View file

@ -0,0 +1,32 @@
---@brief
--- https://www.osohq.com/docs/develop/local-dev/env-setup
---
--- Oso Polar language server.
---
--- `oso-cloud` can be installed by following the instructions
--- [here](https://www.osohq.com/docs/develop/local-dev/env-setup).
---
--- The default `cmd` assumes that the `oso-cloud` binary can be found in the `$PATH`.
---
--- You may need to configure the filetype for Polar (*.polar) files:
---
--- ```
--- autocmd BufNewFile,BufRead *.polar set filetype=polar
--- ```
---
--- or
---
--- ```lua
--- vim.filetype.add({
--- pattern = {
--- ['.*/*.polar'] = 'polar',
--- },
--- })
---
--- Alternatively, you may use a syntax plugin like https://github.com/osohq/polar.vim
---@type vim.lsp.Config
return {
cmd = { 'oso-cloud', 'lsp' },
filetypes = { 'polar' },
}

52
lsp/oxfmt.lua Normal file
View file

@ -0,0 +1,52 @@
--- @brief
---
--- https://github.com/oxc-project/oxc
--- https://oxc.rs/docs/guide/usage/formatter.html
---
--- `oxfmt` is a Prettier-compatible code formatter that supports multiple languages
--- including JavaScript, TypeScript, JSON, YAML, HTML, CSS, Markdown, and more.
--- It can be installed via `npm`:
---
--- ```sh
--- npm i -g oxfmt
--- ```
local util = require 'lspconfig.util'
---@type vim.lsp.Config
return {
cmd = { 'oxfmt', '--lsp' },
filetypes = {
'javascript',
'javascriptreact',
'javascript.jsx',
'typescript',
'typescriptreact',
'typescript.tsx',
'toml',
'json',
'jsonc',
'json5',
'yaml',
'html',
'vue',
'handlebars',
'hbs',
'css',
'scss',
'less',
'graphql',
'markdown',
'mdx',
},
workspace_required = true,
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
-- Oxfmt resolves configuration by walking upward and using the nearest config file
-- to the file being processed. We therefore compute the root directory by locating
-- the closest `.oxfmtrc.json` (or `package.json` fallback) above the buffer.
local root_markers = util.insert_package_json({ '.oxfmtrc.json' }, 'oxfmt', fname)[1]
on_dir(vim.fs.dirname(vim.fs.find(root_markers, { path = fname, upward = true })[1]))
end,
}

View file

@ -1,31 +1,62 @@
--- @brief
---
--- https://github.com/oxc-project/oxc
--- https://oxc.rs/docs/guide/usage/linter.html
---
--- `oxc` is a linter / formatter for JavaScript / Typescript supporting over 500 rules from ESLint and its popular plugins
--- `oxlint` is a linter for JavaScript / TypeScript supporting over 500 rules from ESLint and its popular plugins.
--- It also supports linting framework files (Vue, Svelte, Astro) by analyzing their <script> blocks.
--- It can be installed via `npm`:
---
--- ```sh
--- npm i -g oxlint
--- ```
local util = require 'lspconfig.util'
local util = require("lspconfig.util")
---@type vim.lsp.Config
return {
cmd = { 'oxc_language_server' },
filetypes = {
'javascript',
'javascriptreact',
'javascript.jsx',
'typescript',
'typescriptreact',
'typescript.tsx',
},
workspace_required = true,
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
local root_markers = util.insert_package_json({ '.oxlintrc.json' }, 'oxlint', fname)
on_dir(vim.fs.dirname(vim.fs.find(root_markers, { path = fname, upward = true })[1]))
end,
cmd = { "oxlint", "--lsp" },
filetypes = {
"javascript",
"javascriptreact",
"javascript.jsx",
"typescript",
"typescriptreact",
"typescript.tsx",
"vue",
"svelte",
"astro",
},
workspace_required = true,
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, "LspOxlintFixAll", function()
client:exec_cmd({
title = "Apply Oxlint automatic fixes",
command = "oxc.fixAll",
arguments = { { uri = vim.uri_from_bufnr(bufnr) } },
})
end, {
desc = "Apply Oxlint automatic fixes",
})
end,
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
-- Oxlint resolves configuration by walking upward and using the nearest config file
-- to the file being processed. We therefore compute the root directory by locating
-- the closest `.oxlintrc.json` (or `package.json` fallback) above the buffer.
local root_markers = util.insert_package_json({ ".oxlintrc.json" }, "oxlint", fname)[1]
on_dir(vim.fs.dirname(vim.fs.find(root_markers, { path = fname, upward = true })[1]))
end,
init_options = {
settings = {
-- ['run'] = 'onType',
-- ['configPath'] = nil,
-- ['tsConfigPath'] = nil,
-- ['unusedDisableDirectives'] = 'allow',
["typeAware"] = true,
-- ['disableNestedConfig'] = false,
-- ['fixKind'] = 'safe_fix',
},
},
}

View file

@ -0,0 +1,12 @@
---@brief
---
--- https://github.com/ponylang/pony-language-server
---
--- Language server for the Pony programming language
---@type vim.lsp.Config
return {
cmd = { 'pony-lsp' },
filetypes = { 'pony' },
root_markers = { 'corral.json', '.git' },
}

View file

@ -1,14 +1,15 @@
---@brief
---
--- https://pgtools.dev
--- https://pg-language-server.com
---
--- A collection of language tools and a Language Server Protocol (LSP) implementation for Postgres, focusing on developer experience and reliable SQL tooling.
---@type vim.lsp.Config
return {
cmd = { 'postgrestools', 'lsp-proxy' },
cmd = { 'postgres-language-server', 'lsp-proxy' },
filetypes = {
'sql',
},
root_markers = { 'postgrestools.jsonc' },
root_markers = { 'postgres-language-server.jsonc' },
workspace_required = true,
}

View file

@ -12,7 +12,8 @@ local function set_python_path(command)
}
for _, client in ipairs(clients) do
if client.settings then
client.settings.python = vim.tbl_deep_extend('force', client.settings.python, { pythonPath = path })
client.settings.python =
vim.tbl_deep_extend('force', client.settings.python --[[@as table]], { pythonPath = path })
else
client.config.settings = vim.tbl_deep_extend('force', client.config.settings, { python = { pythonPath = path } })
end
@ -25,12 +26,12 @@ return {
cmd = { 'pyright-langserver', '--stdio' },
filetypes = { 'python' },
root_markers = {
'pyrightconfig.json',
'pyproject.toml',
'setup.py',
'setup.cfg',
'requirements.txt',
'Pipfile',
'pyrightconfig.json',
'.git',
},
settings = {
@ -52,6 +53,7 @@ return {
-- Using client.request() directly because "pyright.organizeimports" is private
-- (not advertised via capabilities), which client:exec_cmd() refuses to call.
-- https://github.com/neovim/neovim/blob/c333d64663d3b6e0dd9aa440e433d346af4a3d81/runtime/lua/vim/lsp/client.lua#L1024-L1030
---@diagnostic disable-next-line: param-type-mismatch
client.request('workspace/executeCommand', params, nil, bufnr)
end, {
desc = 'Organize Imports',

View file

@ -7,6 +7,7 @@
-- replace `<platform>` with one of the following `linux-x64`, `osx-x64`, `win-x64`, `neutral` (for more info on the download location see https://github.com/dotnet/roslyn/issues/71474#issuecomment-2177303207).
-- Download and extract it (nuget's are zip files).
-- - if you chose `neutral` nuget version, then you have to change the `cmd` like so:
-- ```lua
-- cmd = {
-- 'dotnet',
-- '<my_folder>/Microsoft.CodeAnalysis.LanguageServer.dll',
@ -16,6 +17,7 @@
-- fs.joinpath(uv.os_tmpdir(), 'roslyn_ls/logs'),
-- '--stdio',
-- },
-- ```
-- where `<my_folder>` has to be the folder you extracted the nuget package to.
-- - for all other platforms put the extracted folder to neovim's PATH (`vim.env.PATH`)
@ -48,8 +50,7 @@ end
---@param client vim.lsp.Client
local function refresh_diagnostics(client)
local buffers = vim.lsp.get_buffers_by_client_id(client.id)
for _, buf in ipairs(buffers) do
for buf, _ in pairs(vim.lsp.get_client_by_id(client.id).attached_buffers) do
if vim.api.nvim_buf_is_loaded(buf) then
client:request(
vim.lsp.protocol.Methods.textDocument_diagnostic,
@ -97,6 +98,16 @@ local function roslyn_handlers()
}
end
---@param bufname string
---@return boolean
local function is_decompiled(bufname)
local _, endpos = bufname:find('[/\\]MetadataAsSource[/\\]')
if endpos == nil then
return false
end
return vim.fn.finddir(bufname:sub(1, endpos), uv.os_tmpdir()) ~= ''
end
---@type vim.lsp.Config
return {
name = 'roslyn_ls',
@ -118,6 +129,7 @@ return {
local args = command.arguments or {}
local uri, edit = args[1], args[2]
---@diagnostic disable: undefined-field
if uri and edit and edit.newText and edit.range then
local workspace_edit = {
changes = {
@ -130,6 +142,7 @@ return {
},
}
vim.lsp.util.apply_workspace_edit(workspace_edit, client.offset_encoding)
---@diagnostic enable: undefined-field
else
vim.notify('roslyn_ls: completionComplexEdit args not understood: ' .. vim.inspect(args), vim.log.levels.WARN)
end
@ -140,7 +153,7 @@ return {
local bufname = vim.api.nvim_buf_get_name(bufnr)
-- don't try to find sln or csproj for files from libraries
-- outside of the project
if not bufname:match('^' .. fs.joinpath('/tmp/MetadataAsSource/')) then
if not is_decompiled(bufname) then
-- try find solutions root first
local root_dir = fs.root(bufnr, function(fname, _)
return fname:match('%.sln[x]?$') ~= nil
@ -156,6 +169,16 @@ return {
if root_dir then
cb(root_dir)
end
else
-- Decompiled code (example: "/tmp/MetadataAsSource/f2bfba/DecompilationMetadataAsSourceFileProvider/d5782a/Console.cs")
local prev_buf = vim.fn.bufnr('#')
local client = vim.lsp.get_clients({
name = 'roslyn_ls',
bufnr = prev_buf ~= 1 and prev_buf or nil,
})[1]
if client then
cb(client.config.root_dir)
end
end
end,
on_init = {

View file

@ -14,10 +14,20 @@
---@type vim.lsp.Config
return {
cmd = { 'ruby-lsp' },
cmd = function(dispatchers, config)
return vim.lsp.rpc.start(
{ 'ruby-lsp' },
dispatchers,
config and config.root_dir and { cwd = config.cmd_cwd or config.root_dir }
)
end,
filetypes = { 'ruby', 'eruby' },
root_markers = { 'Gemfile', '.git' },
init_options = {
formatter = 'auto',
},
reuse_client = function(client, config)
config.cmd_cwd = config.root_dir
return client.config.cmd_cwd == config.cmd_cwd
end,
}

12
lsp/rumdl.lua Normal file
View file

@ -0,0 +1,12 @@
---@brief
---
--- https://github.com/rvben/rumdl
---
--- Markdown Linter and Formatter written in Rust.
---@type vim.lsp.Config
return {
cmd = { 'rumdl', 'server' },
filetypes = { 'markdown' },
root_markers = { '.git' },
}

View file

@ -105,6 +105,30 @@ return {
capabilities = {
experimental = {
serverStatusNotification = true,
commands = {
commands = {
'rust-analyzer.showReferences',
'rust-analyzer.runSingle',
'rust-analyzer.debugSingle',
},
},
},
},
settings = {
['rust-analyzer'] = {
lens = {
debug = { enable = true },
enable = true,
implementations = { enable = true },
references = {
adt = { enable = true },
enumVariant = { enable = true },
method = { enable = true },
trait = { enable = true },
},
run = { enable = true },
updateTest = { enable = true },
},
},
},
before_init = function(init_params, config)
@ -112,6 +136,24 @@ return {
if config.settings and config.settings['rust-analyzer'] then
init_params.initializationOptions = config.settings['rust-analyzer']
end
---@param command table{ title: string, command: string, arguments: any[] }
vim.lsp.commands['rust-analyzer.runSingle'] = function(command)
local r = command.arguments[1]
local cmd = { 'cargo', unpack(r.args.cargoArgs) }
if r.args.executableArgs and #r.args.executableArgs > 0 then
vim.list_extend(cmd, { '--', unpack(r.args.executableArgs) })
end
local proc = vim.system(cmd, { cwd = r.args.cwd })
local result = proc:wait()
if result.code == 0 then
vim.notify(result.stdout, vim.log.levels.INFO)
else
vim.notify(result.stderr, vim.log.levels.ERROR)
end
end
end,
on_attach = function(_, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspCargoReload', function()

View file

@ -23,15 +23,9 @@
--- Available options are documented [here](https://github.com/shader-slang/slang-vscode-extension/tree/main?tab=readme-ov-file#configurations)
--- or in more detail [here](https://github.com/shader-slang/slang-vscode-extension/blob/main/package.json#L70).
local bin_name = 'slangd'
if vim.fn.has 'win32' == 1 then
bin_name = 'slangd.exe'
end
---@type vim.lsp.Config
return {
cmd = { bin_name },
cmd = { 'slangd' },
filetypes = { 'hlsl', 'shaderslang' },
root_markers = { '.git' },
}

View file

@ -31,6 +31,6 @@ return {
},
},
init_options = {
storageDir = nil,
storageDir = vim.NIL,
},
}

View file

@ -2,28 +2,98 @@
---
--- https://github.com/snyk/snyk-ls
---
--- LSP for Snyk Open Source, Snyk Infrastructure as Code, and Snyk Code.
--- **[Snyk](https://snyk.io)** is a developer security platform that helps you find and fix
--- vulnerabilities in your code, open source dependencies, containers, and infrastructure as code.
---
--- The Snyk Language Server provides real-time security scanning for:
--- - **Snyk Open Source**: Find and fix vulnerabilities in open source dependencies
--- - **Snyk Code**: Find and fix security vulnerabilities in your code
--- - **Snyk Infrastructure as Code**: Find and fix security issues in Kubernetes, Terraform, and other IaC files
---
--- ## Authentication
---
--- **Note**: Currently, only token-based authentication is supported in Neovim.
---
--- 1. Get your API token from https://app.snyk.io/account
--- 2. Set the `SNYK_TOKEN` environment variable:
--- ```sh
--- export SNYK_TOKEN="your-token-here"
--- ```
---
--- ## Trusted Folders
---
--- Snyk requires you to trust directories before scanning them. To avoid being prompted every time:
---
--- ```lua
--- vim.lsp.config('snyk_ls', {
--- init_options = {
--- trustedFolders = {
--- '/Users/yourname/projects', -- Trust your projects directory
--- '/path/to/another/trusted/dir',
--- },
--- },
--- })
--- ```
---
--- **Important**: Trust the top-level directory where you store your repositories, not individual repos.
--- For example, if you work on `/Users/yourname/projects/my-app`, trust `/Users/yourname/projects`.
--- Only trust directories containing code you trust to scan.
---
--- ## Configuration
---
--- Full configuration options available at https://github.com/snyk/snyk-ls#configuration-1
---
--- ### Advanced Configuration
---
--- For **non-default multi-tenant or single-tenant setups**, you may need to specify:
---
--- - `endpoint`: Custom Snyk API endpoint (e.g., `https://api.eu.snyk.io` for EU, or your single-tenant URL)
--- ```
---@type vim.lsp.Config
return {
cmd = { 'snyk-ls' },
cmd = { 'snyk', 'language-server', '-l', 'info' },
root_markers = { '.git', '.snyk' },
filetypes = {
'apex',
'apexcode',
'c',
'cpp',
'cs',
'dart',
'dockerfile',
'elixir',
'eelixir',
'go',
'gomod',
'groovy',
'helm',
'java',
'javascript',
'typescript',
'json',
'kotlin',
'objc',
'objcpp',
'php',
'python',
'requirements',
'helm',
'yaml',
'ruby',
'rust',
'scala',
'swift',
'terraform',
'terraform-vars',
'typescript',
'yaml',
},
settings = {},
-- Configuration from https://github.com/snyk/snyk-ls#configuration-1
init_options = {
activateSnykCode = 'true',
activateSnykOpenSource = 'true', -- Scan open source dependencies
activateSnykCode = 'false', -- Scan your code for vulnerabilities
activateSnykIac = 'true', -- Scan infrastructure as code
integrationName = 'Neovim',
integrationVersion = tostring(vim.version()),
token = os.getenv('SNYK_TOKEN') or vim.NIL,
trustedFolders = {}, -- Add your trusted directories here to avoid being prompted every time
},
}

View file

@ -13,7 +13,7 @@ return {
root_dir = function(bufnr, on_dir)
local filename = vim.api.nvim_buf_get_name(bufnr)
on_dir(
util.root_pattern 'buildServer.json'(filename)
util.root_pattern('buildServer.json', '.bsp')(filename)
or util.root_pattern('*.xcodeproj', '*.xcworkspace')(filename)
-- better to keep it at the end, because some modularized apps contain multiple Package.swift files
or util.root_pattern('compile_commands.json', 'Package.swift')(filename)

View file

@ -8,5 +8,5 @@
return {
cmd = { 'stylua', '--lsp' },
filetypes = { 'lua' },
root_markers = { '.stylua.toml', 'stylua.toml' },
root_markers = { '.stylua.toml', 'stylua.toml', '.editorconfig' },
}

View file

@ -33,6 +33,7 @@ return {
group = vim.api.nvim_create_augroup('lspconfig.svelte', {}),
callback = function(ctx)
-- internal API to sync changes that have not yet been saved to the file system
---@diagnostic disable-next-line: param-type-mismatch
client:notify('$/onDidChangeTsOrJsFile', { uri = ctx.match })
end,
})

View file

@ -1,17 +1,13 @@
---@brief
---
--- https://github.com/psacawa/systemd-language-server
---
--- `systemd-language-server` can be installed via `pip`:
--- ```sh
--- pip install systemd-language-server
--- ```
---
--- Language Server for Systemd unit files
--- Renamed to [systemd_lsp](#systemd_lsp)
---@type vim.lsp.Config
return {
cmd = { 'systemd-language-server' },
filetypes = { 'systemd' },
root_markers = { '.git' },
}
return vim.tbl_extend('force', vim.lsp.config.systemd_lsp, {
on_init = function(...)
vim.deprecate('systemd_ls', 'systemd_lsp', '3.0.0', 'nvim-lspconfig', false)
if vim.lsp.config.systemd_lsp.on_init then
vim.lsp.config.systemd_lsp.on_init(...)
end
end,
})

20
lsp/systemd_lsp.lua Normal file
View file

@ -0,0 +1,20 @@
---@brief
---
--- https://github.com/JFryy/systemd-lsp
---
--- A Language Server Protocol (LSP) implementation for Systemd unit files,
--- providing editing support with syntax highlighting,
--- diagnostics, autocompletion, and documentation.
---
--- `systemd-lsp` can be installed via `cargo`:
--- ```sh
--- cargo install systemd-lsp
--- ```
---
--- A language server implementation for Systemd unit files made in Rust.
---@type vim.lsp.Config
return {
cmd = { 'systemd-lsp' },
filetypes = { 'systemd' },
}

View file

@ -66,6 +66,13 @@ return {
'svelte',
'templ',
},
capabilities = {
workspace = {
didChangeWatchedFiles = {
dynamicRegistration = true,
},
},
},
settings = {
tailwindCSS = {
validate = true,

View file

@ -8,10 +8,13 @@
local function get_command()
local cmd = { 'tblgen-lsp-server' }
local files = vim.fs.find('tablegen_compile_commands.yml', { path = vim.fn.expand('%:p:h'), upward = true })
local files = vim.fs.find(
{ 'tablegen_compile_commands.yml', 'build/tablegen_compile_commands.yml' },
{ path = vim.fn.expand('%:p:h'), upward = true, type = 'file' }
)
if #files > 0 then
local file = files[1]
table.insert(cmd, '--tablegen-compilation-database=' .. vim.fs.dirname(file) .. '/tablegen_compile_commands.yml')
table.insert(cmd, '--tablegen-compilation-database=' .. file)
end
return cmd

22
lsp/tclsp.lua Normal file
View file

@ -0,0 +1,22 @@
---@brief
---
--- https://github.com/nmoroze/tclint
---
--- `tclsp`, a language server for Tcl
---
--- `tclsp` can be installed via `pipx`:
--- ```sh
--- pipx install tclint
--- ```
---
--- Or via `pip`:
--- ```sh
--- pip install tclint
--- ```
---@type vim.lsp.Config
return {
cmd = { 'tclsp' },
filetypes = { 'tcl', 'sdc', 'xdc', 'upf' },
root_markers = { 'tclint.toml', '.tclint', 'pyproject.toml', '.git' },
}

View file

@ -4,9 +4,30 @@
---
--- Language server for various bash scripts such as Arch PKGBUILD, Gentoo ebuild, Termux build.sh, etc.
local util = require('lspconfig').util
---@type vim.lsp.Config
return {
cmd = { 'termux-language-server' },
filetypes = { 'PKGBUILD' },
root_markers = { '.git' },
root_dir = function(bufnr, on_dir)
local patterns = {
-- Termux
'build.sh',
'*.subpackage.sh',
-- Arch/MSYS2
'PKGBUILD',
'makepkg.conf',
'*.install',
-- Gentoo
'make.conf',
'color.map',
'*.ebuild',
'*.eclass',
}
local fname = vim.api.nvim_buf_get_name(bufnr)
local match = util.root_pattern(patterns)(fname)
if match then
on_dir(vim.fs.root(match, '.git') or match)
end
end,
}

View file

@ -111,25 +111,23 @@ local function buf_find_envs(client, bufnr)
end
local function buf_change_env(client, bufnr)
local new
vim.ui.input({ prompt = 'New environment name: ' }, function(input)
new = input
end)
if not new or new == '' then
return vim.notify('No environment name provided', vim.log.levels.WARN)
end
local pos = vim.api.nvim_win_get_cursor(0)
return client:exec_cmd({
title = 'change_environment',
command = 'texlab.changeEnvironment',
arguments = {
{
textDocument = { uri = vim.uri_from_bufnr(bufnr) },
position = { line = pos[1] - 1, character = pos[2] },
newName = tostring(new),
if not input or input == '' then
return vim.notify('No environment name provided', vim.log.levels.WARN)
end
local pos = vim.api.nvim_win_get_cursor(0)
return client:exec_cmd({
title = 'change_environment',
command = 'texlab.changeEnvironment',
arguments = {
{
textDocument = { uri = vim.uri_from_bufnr(bufnr) },
position = { line = pos[1] - 1, character = pos[2] },
newName = tostring(input),
},
},
},
}, { bufnr = bufnr })
}, { bufnr = bufnr })
end)
end
---@type vim.lsp.Config

View file

@ -4,11 +4,11 @@
--- An integrated language service for Typst [taɪpst]. You can also call it "微霭" [wēi ǎi] in Chinese.
---
--- Currently some of Tinymist's workspace commands are supported, namely:
--- `LspTinymistExportSvg`, `LspTinymistExportPng`, `LspTinymistExportPdf
--- `LspTinymistExportSvg`, `LspTinymistExportPng`, `LspTinymistExportPdf`,
--- `LspTinymistExportMarkdown`, `LspTinymistExportText`, `LspTinymistExportQuery`,
--- `LspTinymistExportAnsiHighlight`, `LspTinymistGetServerInfo`,
--- `LspTinymistGetDocumentTrace`, `LspTinymistGetWorkspaceLabels`, and
--- `LspTinymistGetDocumentMetrics`.
--- `LspTinymistGetDocumentTrace`, `LspTinymistGetWorkspaceLabels`,
--- `LspTinymistGetDocumentMetrics`, and `LspTinymistPinMain`.
---@param command_name string
---@param client vim.lsp.Client
@ -17,10 +17,7 @@
local function create_tinymist_command(command_name, client, bufnr)
local export_type = command_name:match 'tinymist%.export(%w+)'
local info_type = command_name:match 'tinymist%.(%w+)'
if info_type and info_type:match '^get' then
info_type = info_type:gsub('^get', 'Get')
end
local cmd_display = export_type or info_type
local cmd_display = export_type or info_type:gsub('^get', 'Get'):gsub('^pin', 'Pin')
---@return nil
local function run_tinymist_command()
local arguments = { vim.api.nvim_buf_get_name(bufnr) }
@ -30,8 +27,7 @@ local function create_tinymist_command(command_name, client, bufnr)
if err then
return vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR)
end
-- If exporting, show the string result; else, show the table for inspection
vim.notify(export_type and res or vim.inspect(res), vim.log.levels.INFO)
vim.notify(vim.inspect(res), vim.log.levels.INFO)
end
return client:exec_cmd({
title = title_str,
@ -64,6 +60,7 @@ return {
'tinymist.getDocumentTrace',
'tinymist.getWorkspaceLabels',
'tinymist.getDocumentMetrics',
'tinymist.pinMain',
} do
local cmd_func, cmd_name, cmd_desc = create_tinymist_command(command, client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'Lsp' .. cmd_name, cmd_func, { nargs = 0, desc = cmd_desc })

View file

@ -6,6 +6,6 @@
---@type vim.lsp.Config
return {
cmd = { 'tofu-ls', 'serve' },
filetypes = { 'opentofu', 'opentofu-vars' },
filetypes = { 'opentofu', 'opentofu-vars', 'terraform' },
root_markers = { '.terraform', '.git' },
}

View file

@ -33,6 +33,8 @@
--- - organize imports
--- - remove unused code
---
--- Use the `:LspTypescriptGoToSourceDefinition` command to navigate to the source definition of a symbol (e.g., jump to the original implementation instead of type definitions).
---
--- ### Monorepo support
---
--- `ts_ls` supports monorepos by default. It will automatically find the `tsconfig.json` or `jsconfig.json` corresponding to the package you are working on.
@ -62,10 +64,14 @@ return {
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- exclude deno
local deno_path = vim.fs.root(bufnr, { 'deno.json', 'deno.jsonc', 'deno.lock' })
local project_root = vim.fs.root(bufnr, root_markers)
if deno_path and (not project_root or #deno_path >= #project_root) then
return
end
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()
on_dir(project_root)
on_dir(project_root or vim.fn.getcwd())
end,
handlers = {
-- handle rename request for certain code actions like extracting functions / types
@ -87,7 +93,7 @@ return {
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
local file_uri, position, references = unpack(command.arguments)
local quickfix_items = vim.lsp.util.locations_to_items(references, client.offset_encoding)
local quickfix_items = vim.lsp.util.locations_to_items(references --[[@as any]], client.offset_encoding)
vim.fn.setqflist({}, ' ', {
title = command.title,
items = quickfix_items,
@ -98,12 +104,13 @@ return {
})
vim.lsp.util.show_document({
uri = file_uri,
uri = file_uri --[[@as string]],
range = {
start = position,
['end'] = position,
start = position --[[@as lsp.Position]],
['end'] = position --[[@as lsp.Position]],
},
}, client.offset_encoding)
---@diagnostic enable: assign-type-mismatch
vim.cmd('botright copen')
end,
@ -119,8 +126,30 @@ return {
vim.lsp.buf.code_action({
context = {
only = source_actions,
diagnostics = {},
},
})
end, {})
-- Go to source definition command
vim.api.nvim_buf_create_user_command(bufnr, 'LspTypescriptGoToSourceDefinition', function()
local win = vim.api.nvim_get_current_win()
local params = vim.lsp.util.make_position_params(win, client.offset_encoding)
client:exec_cmd({
command = '_typescript.goToSourceDefinition',
title = 'Go to source definition',
arguments = { params.textDocument.uri, params.position },
}, { bufnr = bufnr }, function(err, result)
if err then
vim.notify('Go to source definition failed: ' .. err.message, vim.log.levels.ERROR)
return
end
if not result or vim.tbl_isempty(result) then
vim.notify('No source definition found', vim.log.levels.INFO)
return
end
vim.lsp.util.show_document(result[1], client.offset_encoding, { focus = true })
end)
end, { desc = 'Go to source definition' })
end,
}

View file

@ -16,14 +16,19 @@
---@type vim.lsp.Config
return {
cmd = { 'tsgo', '--lsp', '--stdio' },
cmd = function(dispatchers, config)
local cmd = 'tsgo'
local local_cmd = (config or {}).root_dir and config.root_dir .. '/node_modules/.bin/tsgo'
if local_cmd and vim.fn.executable(local_cmd) == 1 then
cmd = local_cmd
end
return vim.lsp.rpc.start({ cmd, '--lsp', '--stdio' }, dispatchers)
end,
filetypes = {
'javascript',
'javascriptreact',
'javascript.jsx',
'typescript',
'typescriptreact',
'typescript.tsx',
},
root_dir = function(bufnr, on_dir)
-- The project root is where the LSP can be started from
@ -34,6 +39,12 @@ return {
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- exclude deno
if vim.fs.root(bufnr, { 'deno.json', 'deno.jsonc', 'deno.lock' }) then
return
end
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()

View file

@ -10,5 +10,5 @@
return {
cmd = { 'ty', 'server' },
filetypes = { 'python' },
root_markers = { 'ty.toml', 'pyproject.toml', '.git' },
root_markers = { 'ty.toml', 'pyproject.toml', 'setup.py', 'setup.cfg', 'requirements.txt', '.git' },
}

View file

@ -7,6 +7,6 @@
---@type vim.lsp.Config
return {
cmd = { 'vale-ls' },
filetypes = { 'markdown', 'text', 'tex', 'rst' },
filetypes = { 'asciidoc', 'markdown', 'text', 'tex', 'rst', 'html', 'xml' },
root_markers = { '.vale.ini' },
}

View file

@ -1,9 +1,13 @@
---@brief
---
--- Renamed to [vue_ls](#vue_ls)
---
---
vim.deprecate('volar', 'vue_ls', '3.0.0', 'nvim-lspconfig', false)
---@type vim.lsp.Config
return vim.lsp.config.vue_ls
return vim.tbl_extend('force', vim.lsp.config.vue_ls, {
on_init = function(...)
vim.deprecate('volar', 'vue_ls', '3.0.0', 'nvim-lspconfig', false)
if vim.lsp.config.vue_ls.on_init then
vim.lsp.config.vue_ls.on_init(...)
end
end,
})

View file

@ -1,10 +1,13 @@
---@brief
---
--- https://github.com/coq-community/vscoq
--- Renamed to [vsrocq](#vsrocq)
---@type vim.lsp.Config
return {
cmd = { 'vscoqtop' },
filetypes = { 'coq' },
root_markers = { '_CoqProject', '.git' },
}
return vim.tbl_extend('force', vim.lsp.config.vsrocq, {
on_init = function(...)
vim.deprecate('vscoqtop', 'vsrocq', '3.0.0', 'nvim-lspconfig', false)
if vim.lsp.config.vsrocq.on_init then
vim.lsp.config.vsrocq.on_init(...)
end
end,
})

10
lsp/vsrocq.lua Normal file
View file

@ -0,0 +1,10 @@
---@brief
---
--- https://github.com/rocq-prover/vsrocq
---@type vim.lsp.Config
return {
cmd = { 'vsrocqtop' },
filetypes = { 'coq' },
root_markers = { '_RocqProject', '_CoqProject', '.git' },
}

View file

@ -88,6 +88,12 @@ return {
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- exclude deno
if vim.fs.root(bufnr, { 'deno.json', 'deno.jsonc', 'deno.lock' }) then
return
end
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()

View file

@ -0,0 +1,85 @@
---@brief
---
--- https://github.com/wc-toolkit/wc-language-server
---
--- Web Components Language Server provides intelligent editor support for Web Components and custom elements.
--- It offers advanced HTML diagnostics, completion, and validation for custom elements, including support for
--- attribute types, deprecation, and duplicate attribute detection.
---
--- The language server uses the [Custom Elements Manifest](https://github.com/webcomponents/custom-elements-manifest)
--- to generate component integration and validation information
---
--- `wc-language-server` can be installed by following the instructions at the [GitHub repository](https://github.com/wc-toolkit/wc-language-server/blob/main/packages/neovim/README.md).
---
--- The default `cmd` assumes that the `wc-language-server` binary can be found in `$PATH`.
---
--- Alternatively, you can install it via [mason.nvim](https://github.com/williamboman/mason.nvim):
--- ```vim
--- :MasonInstall wc-language-server
--- ```
---
--- ## Configuration
---
--- The language server reads settings from `wc.config.js` (or `.ts/.mjs/.cjs`) at the project root.
--- Use it to customize manifest sources, file scoping, and diagnostic behavior.
---
--- Example `wc.config.js`:
--- ```js
--- export default {
--- // Fetch manifest from a custom path or URL
--- manifestSrc: './dist/custom-elements.json',
---
--- // Narrow which files opt into the language server
--- include: ['src/**/*.ts', 'src/**/*.html'],
---
--- // Skip specific globs
--- exclude: ['**/*.stories.ts'],
---
--- // Per-library overrides
--- libraries: {
--- '@your/pkg': {
--- manifestSrc: 'https://cdn.example.com/custom-elements.json',
--- tagFormatter: (tag) => tag.replace(/^x-/, 'my-'),
--- },
--- },
---
--- // Customize diagnostic severity levels
--- diagnosticSeverity: {
--- duplicateAttribute: 'warning',
--- unknownElement: 'info',
--- },
--- };
--- ```
---
--- See the [configuration documentation](https://github.com/wc-toolkit/wc-language-server#configuration) for more details.
---
---@type vim.lsp.Config
return {
init_options = { hostInfo = 'neovim' },
cmd = { 'wc-language-server', '--stdio' },
filetypes = {
'html',
'javascriptreact',
'typescriptreact',
'astro',
'svelte',
'vue',
'markdown',
'mdx',
'javascript',
'typescript',
'css',
'scss',
'less',
},
root_markers = {
'wc.config.js',
'wc.config.ts',
'wc.config.mjs',
'wc.config.cjs',
'custom-elements.json',
'package.json',
'.git',
},
}

View file

@ -72,3 +72,16 @@ vim.api.nvim_create_autocmd("BufWritePost", {
end
end,
})
-- Disable LSP in fugitive buffers
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
local bufnr = args.buf
if vim.api.nvim_buf_get_name(bufnr):match("^fugitive://") then
if client then
vim.lsp.stop_client(client.id)
end
end
end,
})

View file

@ -43,14 +43,20 @@ set("n", "<Right>", "<C-w>l")
-- Duplicate line
set("n", "<leader>dl", "mzyyp`zj")
-- Add all diagnostics to quickfix list
set("n", "<leader>xx", function()
vim.diagnostic.setqflist({ open = true })
end)
-- Start merge conflict resolution
set("n", "<leader>gm", ":Git mergetool<CR>:only<CR>")
-- Diff get local
set("n", "<leader>dgl", "/\\V======<CR>d<CR>dd/\\V>>>>>><CR>dd")
-- Toggle vimdiff for side-by-side comparison
set("n", "<leader>dd", ":if &diff | diffoff | only | else | Gvdiffsplit! | endif<CR>")
-- Diff get remote
set("n", "<leader>dgr", "V/\\V======<CR>d<CR>dd/\\V>>>>>><CR>dd")
-- Diff get both
set("n", "<leader>dgb", "dd/\\V======<CR>dd/\\V>>>>>><CR>dd")
-- Git conflict resolution (choose local/remote/both)
set("n", "<leader>dl", 'j?HEAD<CR>"_dd/\\V======<CR>V/\\V>>>>>><CR>"_dk')
set("n", "<leader>dc", 'j?HEAD<CR>"_dd/\\V======<CR>V/\\V>>>>>><CR>"_dk')
set("n", "<leader>dr", 'j?HEAD<CR>V/\\V======<CR>"_d/\\V>>>>>><CR>"_ddk')
set("n", "<leader>di", 'j?HEAD<CR>V/\\V======<CR>"_d/\\V>>>>>><CR>"_ddk')
set("n", "<leader>db", 'j?HEAD<CR>"_dd/\\V======<CR>"_dd/\\V>>>>>><CR>"_dd2k')

View file

@ -1,11 +0,0 @@
return {
on_attach = function(_, bufnr)
-- Format document on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
require("conform").format({ async = true, lsp_fallback = true })
end,
})
end
}

View file

@ -1 +0,0 @@
return {}

View file

@ -1 +0,0 @@
return {}

View file

@ -1,11 +0,0 @@
return {
on_attach = function(_, bufnr)
-- Format document on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
require("conform").format({ async = true, lsp_fallback = true })
end,
})
end
}

View file

@ -1,48 +0,0 @@
return {
settings = {
gopls = {
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
parameterNames = true,
rangeVariableTypes = true,
},
},
},
on_attach = function(_, bufnr)
-- Format document on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
vim.lsp.buf.format()
end,
})
-- run the current go file in a vertical split terminal pane
vim.keymap.set("n", "<leader><CR>", "<cmd>vsplit term://go run %<CR>")
-- open the Go scratchpad
vim.keymap.set("n", "<leader>q", "<cmd>e ~/personal/Go/test/main.go | normal 6G2|<CR>")
-- Auto organize imports on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
local params = vim.lsp.util.make_range_params()
params.context = { only = { "source.organizeImports" } }
local result = vim.lsp.buf_request_sync(bufnr, "textDocument/codeAction", params, 1000)
for _, res in pairs(result or {}) do
for _, r in pairs(res.result or {}) do
if r.edit then
vim.lsp.util.apply_workspace_edit(r.edit, "utf-8")
else
vim.lsp.buf.execute_command(r.command)
end
end
end
end,
})
end,
}

View file

@ -1,11 +0,0 @@
return {
on_attach = function(_, bufnr)
-- Format document on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
require("conform").format({ async = true, lsp_fallback = true })
end,
})
end
}

View file

@ -1,17 +0,0 @@
return {
on_attach = function(_, bufnr)
-- Format document on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
-- check that biome lsp is running
local biome = vim.lsp.get_clients({ buffer = bufnr, name = "biome" })
if #biome == 0 then
vim.lsp.buf.format()
else
vim.lsp.buf.format({ filter = function(client) return client.name == "biome" end })
end
end,
})
end
}

View file

@ -1,10 +0,0 @@
return {
settings = {
Lua = {
workspace = {
checkThirdParty = false,
library = { vim.env.VIMRUNTIME },
}
},
},
}

View file

@ -1 +0,0 @@
return {}

View file

@ -1 +0,0 @@
return {}

View file

@ -1,6 +0,0 @@
return {
on_attach = function(client, _)
-- Just want ts_ls in path, I don't want it to do anything
client.stop()
end
}

View file

@ -1,11 +0,0 @@
return {
on_attach = function(_, bufnr)
-- Format document on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
require("conform").format({ async = true, lsp_fallback = true })
end,
})
end
}

9
lua/custom/lspconfig.lua Normal file
View file

@ -0,0 +1,9 @@
local mason_lspconfig = require("mason-lspconfig")
local disabled_lsps = { "ts_ls" }
for _, server_name in ipairs(mason_lspconfig.get_installed_servers()) do
if not vim.tbl_contains(disabled_lsps, server_name) then
vim.lsp.enable(server_name)
end
end

View file

@ -7,35 +7,41 @@ return {
sql = { "sqlfmt" },
bash = { "shfmt" },
go = { "gofumpt", "goimports" },
html = { "biome", "prettier" },
yaml = { "prettier" },
json = { "jq" },
css = { "prettier" },
html = { "oxfmt" },
yaml = { "oxfmt" },
json = { "oxfmt" },
css = { "oxfmt" },
xml = { "xmlformatter" },
svg = { "xmlformatter" },
javascript = { "biome", "prettier" },
javascriptreact = { "biome", "prettier" },
typescript = { "biome", "prettier" },
typescriptreact = { "biome", "prettier" },
vue = { "oxfmt" },
markdown = { "oxfmt" },
terraform = { "tfmt" },
javascript = { "oxfmt" },
javascriptreact = { "oxfmt" },
typescript = { "oxfmt" },
typescriptreact = { "oxfmt" },
["*"] = { "trim_whitespace" },
},
formatters = {
biome = {
tfmt = {
condition = function()
return vim.uv.fs_realpath("biome.json") ~= nil
return vim.bo.filetype == "terraform"
end,
command = "biome",
args = {
"check",
"--fix",
"--unsafe",
"$FILENAME",
},
command = "terraform",
args = { "fmt", "$FILENAME" },
stdin = false,
},
oxfmt = {
condition = function()
return vim.uv.fs_realpath(".oxfmtrc.json") ~= nil
end,
command = "oxfmt",
args = "$FILENAME",
stdin = false,
},
},
format_on_save = {
lsp_fallback = true,
lsp_fallback = false,
async = false,
timeout_ms = 500,
},
@ -47,6 +53,18 @@ return {
lsp_fallback = true,
async = false,
timeout_ms = 1000,
formatting_options = {
formatters = {
oxfmt = {
condition = function()
return vim.uv.fs_realpath(".oxfmtrc.json") ~= nil
end,
command = "oxlint",
args = { "--fix-dangerously", "$FILENAME" },
stdin = false,
},
},
},
})
end, { desc = "Format file or range (in visual mode)" })
end,

View file

@ -3,8 +3,8 @@ return {
event = "VeryLazy",
opts = {},
keys = {
{ "<leader>goa", "<cmd>GoAddTag<CR>", desc = "Add struct tags"},
{ "<leader>gor", "<cmd>GoRmTag<CR>", desc = "Remove struct tags"},
{ "<leader>got", "<cmd>GoAddAllTest<CR>", desc = "Add all tests"},
-- { "<leader>goa", "<cmd>GoAddTag<CR>", desc = "Add struct tags"},
-- { "<leader>gor", "<cmd>GoRmTag<CR>", desc = "Remove struct tags"},
-- { "<leader>got", "<cmd>GoAddAllTest<CR>", desc = "Add all tests"},
},
}

View file

@ -1,8 +1,13 @@
return {
"mason-org/mason-lspconfig.nvim",
opts = {},
setup = {
automatic_enable = false,
},
dependencies = {
{ "mason-org/mason.nvim", opts = {} },
"neovim/nvim-lspconfig",
},
config = function()
require("custom.lspconfig")
end,
}

View file

@ -1,27 +0,0 @@
return {
"mfussenegger/nvim-lint",
event = {
"BufReadPre",
"BufNewFile",
},
config = function()
local lint = require("lint")
lint.linters_by_ft = {
go = { "golangcilint" },
javascript = { "biomejs" },
typescript = { "biomejs" },
javascriptreact = { "biomejs" },
typescriptreact = { "biomejs" },
}
local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true })
vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave" }, {
group = lint_augroup,
callback = function()
lint.try_lint()
end,
})
end,
}

Some files were not shown because too many files have changed in this diff Show more