AstroLsp
AstroLsp用于在 AstroNvim 中配置 LSP 即语言服务器。neovim 中集成了一个 lsp 客户端,AstroLsp 主要就是配置来实现自动安装对应语言的 LSP 服务器,它主要提供了对以下插件的集成:
- nvim-lspconfig: neovim 官方提供的 lsp 服务器配置插件
- mason.nvim: 帮助我们自动安装 lsp 服务器
- none-ls.nvim: 它将一些非 lsp 服务器的工具(主要是 format 和 lint 工具)包装为 lsp 接口
mason
该插件能过帮助我们轻松安装外部工具,例如 lsp 服务器、dap 服务器、linter 和 formater 工具。
默认情况下他们会安装到 ~/.local/share/nvim/mason
目录下,其中还存在一个 bin/
目录来放置可执行程序(软连接)。该 bin/
目录会被 mason 设置到 Neovim 进程的 PATH 中,从而运行从 Neovim 内置函数(shell、终端等)以及其他第三方插件无缝访问。
Note
mason 插件有很多的依赖,例如 git、pip、npm 等,他们是安装这些工具的核心命令
mason 工具提供了几个管理命令:
:Mason
: 交互窗口,在其中 i-安装 u-更新 X-卸载:MasonUpdate
: 更新所有工具:MasonInstall <package>
: 安装指定工具:MasonUninstall <package>
: 卸载指定工具:MasonUninstallAll
: 卸载所有工具:MasonLog
: 打开日志文件
nvim-lspconfig and mason-lspconfig
nvim-lspconfig 插件是官方提供的用于配置 lsp 服务器,之后通过:
-- 配置特定 lsp server 例如 pyright
-- opts 是 lspconfig 的配置项目
require('lspconfig')[server_name].setup(opts)
但是它需要你手动安装 lsp 服务器,因此就需要 mason 插件来安装。而mason-lspconfig来沟通两者,来自动通过 mason 安装 lsp 服务器并自动应用 nvim-lspconfig 中的默认配置(甚至不需要你在运行上面的初始化语句):
local DEFAULT_SETTINGS = {
---@type string[]
ensure_installed = {}, -- 自动安装
-- Can either be:
-- - false: Servers are not automatically installed.
-- - true: All servers set up via lspconfig are automatically installed.
-- - { exclude: string[] }: All servers set up via lspconfig, except the ones provided in the list, are automatically installed.
---@type boolean | {exclude: string[]}
-- 即 lsp 服务器由 lspconfig 配置完成,由 mason-lspconfig 自动安装
automatic_installation = false,
-- nil 不要自动配置 lsp 服务器
--
---@type table<string, fun(server_name: string)>?
handlers = nil,
handlers = {
function (server_name) -- default handler (自动配置所有 lsp 服务器)
require("lspconfig")[server_name].setup {}
end,
-- 对特定语言进行配置
["lua_ls"] = function()
local lspconfig = require("lspconfig")
lspconfig.lua_ls.setup {
settings = {
Lua = {
diagnostics = { globals = { "vim" }}
}
}
}
end,
}
}
Tips
说白了就是将 lspconfig 的配置迁移到 mason-lspconfig 的 handlers 中,并且添加了自动安装的功能。
null-ls and mason-null-ls
null-ls 将一些格式化、linter 工具进行包装来为兼容 lsp 协议的接口来当作 lsp 服务器使用。对他的设置只需要添加需要的源即可:
local null_ls = require("null-ls")
-- Check supported formatters and linters
-- https://github.com/nvimtools/none-ls.nvim/tree/main/lua/null-ls/builtins/formatting
-- https://github.com/nvimtools/none-ls.nvim/tree/main/lua/null-ls/builtins/diagnostics
null_ls.setup({
sources = {
null_ls.builtins.formatting.stylua,
null_ls.builtins.completion.spell,
},
})
同样要想让源真正的生效 PATH 中必须存在对应的工具,他可以使用 mason 来安装,而mason-null-ls.nvim就是让我们自动安装并启用对应源的插件,它沟通了 mason 和 null-ls 这两个插件:
local DEFAULT_SETTINGS = {
-- A list of sources to install if they're not already installed.
-- This setting has no relation with the `automatic_installation` setting.
ensure_installed = {},
-- Enable or disable null-ls methods to get set up
-- This setting is useful if some functionality is handled by other plugins such as `conform` and `nvim-lint`
methods = {
diagnostics = true,
formatting = true,
code_actions = true,
completion = true,
hover = true,
},
-- Run `require("null-ls").setup`.
-- Will automatically install masons tools based on selected sources in `null-ls`.
-- Can also be an exclusion list.
-- Example: `automatic_installation = { exclude = { "rust_analyzer", "solargraph" } }`
automatic_installation = false,
-- See [#handlers-usage](#handlers-usage) section
-- handlers = nil,
handlers = {
function() end, -- disables automatic setup of all null-ls sources
stylua = function(source_name, methods)
local null_ls = require 'null-ls'
null_ls.register(null_ls.builtins.formatting.stylua)
end,
shfmt = function(source_name, methods)
-- custom logic
require('mason-null-ls').default_setup(source_name, methods) -- to maintain default behavior
end,
},
}
Tips
他的 handlers 和 mason-lspconfig 一样,如果为 nil 表示配置源由 null-ls 自己设置,可以使用 handlers = {}
来自动安装并配置(这是 AstroNvim 的默认配置)
它还有一个就是所有的源由 null-ls 配置来让 mason-null-ls 自动安装:
require("mason").setup()
require("null-ls").setup({
sources = {
-- all sources go here.
}
})
require("mason-null-ls").setup({
ensure_installed = nil,
automatic_installation = true,
})
astrolsp
在安装模版中它在lua/plugin/astrolsp.lua
中被引入,因此配置也在这里进行。它的配置完全遵循lazy规范:
---@type AstroLSPConfig
local opts = {
-- Configuration table of features provided by AstroLSP
features = {
codelens = true, -- enable/disable codelens refresh on start
inlay_hints = false, -- enable/disable inlay hints on start
semantic_tokens = true, -- enable/disable semantic token highlighting
},
-- Configure buffer local auto commands to add when attaching a language server
autocmds = {
-- first key is the `augroup` (:h augroup)
lsp_document_highlight = {
-- condition to create/delete auto command group
-- can either be a string of a client capability or a function of `fun(client, bufnr): boolean`
-- condition will be resolved for each client on each execution and if it ever fails for all clients,
-- the auto commands will be deleted for that buffer
cond = "textDocument/documentHighlight",
-- list of auto commands to set
{
-- events to trigger
event = { "CursorHold", "CursorHoldI" },
-- the rest of the autocmd options (:h nvim_create_autocmd)
desc = "Document Highlighting",
callback = function() vim.lsp.buf.document_highlight() end,
},
{
event = { "CursorMoved", "CursorMovedI", "BufLeave" },
desc = "Document Highlighting Clear",
callback = function() vim.lsp.buf.clear_references() end,
},
},
},
-- Configure buffer local user commands to add when attaching a language server
commands = {
Format = {
function() vim.lsp.buf.format() end,
-- condition to create the user command
-- can either be a string of a client capability or a function of `fun(client, bufnr): boolean`
cond = "textDocument/formatting",
-- the rest of the user command options (:h nvim_create_user_command)
desc = "Format file with LSP",
},
},
-- Configure default capabilities for language servers (`:h vim.lsp.protocol.make_client.capabilities()`)
capabilities = {
textDocument = {
foldingRange = { dynamicRegistration = false },
},
},
-- Configure language servers for `lspconfig` (`:h lspconfig-setup`)
config = {
lua_ls = {
settings = {
Lua = {
hint = { enable = true, arrayIndex = "Disable" },
},
},
},
clangd = {
capabilities = {
offsetEncoding = "utf-8",
},
},
},
-- A custom flags table to be passed to all language servers (`:h lspconfig-setup`)
flags = {
exit_timeout = 5000,
},
-- Configuration options for controlling formatting with language servers
formatting = {
-- control auto formatting on save
format_on_save = {
-- enable or disable format on save globally
enabled = true,
-- enable format on save for specified filetypes only
allow_filetypes = {
"go",
},
-- disable format on save for specified filetypes
ignore_filetypes = {
"python",
},
},
-- disable formatting capabilities for specific language servers
disabled = {
"lua_ls",
},
-- default format timeout
timeout_ms = 1000,
-- fully override the default formatting function
filter = function(client) return true end,
},
-- Configure how language servers get set up
handlers = {
-- default handler, first entry with no key
function(server, opts) require("lspconfig")[server].setup(opts) end,
-- custom function handler for pyright
pyright = function(_, opts) require("lspconfig").pyright.setup(opts) end,
-- set to false to disable the setup of a language server
rust_analyzer = false,
},
-- Configure `vim.lsp.handlers`
lsp_handlers = {
["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded", silent = true }),
["textDocument/signatureHelp"] = false, -- set to false to disable any custom handlers
},
-- Configuration of mappings added when attaching a language server during the core `on_attach` function
-- The first key into the table is the vim map mode (`:h map-modes`), and the value is a table of entries to be passed to `vim.keymap.set` (`:h vim.keymap.set`):
-- - The key is the first parameter or the vim mode (only a single mode supported) and the value is a table of keymaps within that mode:
-- - The first element with no key in the table is the action (the 2nd parameter) and the rest of the keys/value pairs are options for the third parameter.
-- There is also a special `cond` key which can either be a string of a language server capability or a function with `client` and `bufnr` parameters that returns a boolean of whether or not the mapping is added.
mappings = {
-- map mode (:h map-modes)
n = {
-- a binding with no condition and therefore is always added
gl = {
function() vim.diagnostic.open_float() end,
desc = "Hover diagnostics",
},
-- condition for only server with declaration capabilities
gD = {
function() vim.lsp.buf.declaration() end,
desc = "Declaration of current symbol",
cond = "textDocument/declaration",
},
-- condition with a full function with `client` and `bufnr`
["<leader>uY"] = {
function() require("astrolsp.toggles").buffer_semantic_tokens() end,
desc = "Toggle LSP semantic highlight (buffer)",
cond = function(client, bufnr)
return client.server_capabilities.semanticTokensProvider and vim.lsp.semantic_tokens
end,
},
},
},
-- A list like table of servers that should be setup, useful for enabling language servers not installed with Mason.
servers = { "dartls" },
-- A custom `on_attach` function to be run after the default `on_attach` function, takes two parameters `client` and `bufnr` (`:h lspconfig-setup`)
on_attach = function(client, bufnr) client.server_capabilities.semanticTokensProvider = nil end,
}