refactor: auto-generate language configuration (#1584)

Refactor the monolithic `lvim.lang` design into a more modular approach.

IMPORTANT: run `:LvimUpdate` in order to generate the new ftplugin template files.
This commit is contained in:
kylo252 2021-10-03 16:13:46 +02:00 committed by GitHub
parent 3e1cd1ec23
commit d01ba08eae
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 4AEE18F83AFDEB23
98 changed files with 1127 additions and 1567 deletions

View file

@ -1 +0,0 @@
require("lsp").setup "asm"

View file

@ -1 +0,0 @@
require("lsp").setup "beancount"

View file

@ -1 +0,0 @@
require("lsp").setup "bicep"

View file

@ -1,4 +0,0 @@
require("lsp").setup "c"
-- TODO get from dap
-- require("lang.c").dap()

View file

@ -1 +0,0 @@
require("lsp").setup "clojure"

View file

@ -1 +0,0 @@
require("lsp").setup "cmake"

View file

@ -1 +0,0 @@
require("lsp").setup "cpp"

View file

@ -1 +0,0 @@
require("lsp").setup "crystal"

View file

@ -1 +0,0 @@
require("lsp").setup "cs"

View file

@ -1 +0,0 @@
require("lsp").setup "css"

View file

@ -1 +0,0 @@
require("lsp").setup "d"

View file

@ -1 +0,0 @@
require("lsp").setup "dart"

View file

@ -1 +0,0 @@
require("lsp").setup "dockerfile"

View file

@ -1,10 +0,0 @@
require("lsp").setup "elixir"
vim.api.nvim_buf_set_option(0, "commentstring", "# %s")
-- TODO: do we need this?
-- needed for the LSP to recognize elixir files (alternatively just use elixir-editors/vim-elixir)
-- vim.cmd [[
-- au BufRead,BufNewFile *.ex,*.exs set filetype=elixir
-- au BufRead,BufNewFile *.eex,*.leex,*.sface set filetype=eelixir
-- au BufRead,BufNewFile mix.lock set filetype=elixir
-- ]]

View file

@ -1 +0,0 @@
require("lsp").setup "elm"

View file

@ -1 +0,0 @@
require("lsp").setup "erlang"

View file

@ -1,9 +0,0 @@
require("lsp").setup "erlang"
-- TODO: do we need this?
-- needed for the LSP to recognize elixir files (alternatively just use elixir-editors/vim-elixir)
-- vim.cmd [[
-- au BufRead,BufNewFile *.ex,*.exs set filetype=elixir
-- au BufRead,BufNewFile *.eex,*.leex,*.sface set filetype=eelixir
-- au BufRead,BufNewFile mix.lock set filetype=elixir
-- ]]

View file

@ -1 +0,0 @@
require("lsp").setup "fish"

View file

@ -1 +0,0 @@
require("lsp").setup "fortran"

View file

@ -1 +0,0 @@
require("lsp").setup "gdscript"

View file

@ -1 +0,0 @@
require("lsp").setup "go"

View file

@ -1 +0,0 @@
require("lsp").setup "graphql"

View file

@ -1 +0,0 @@
require("lsp").setup "haskell"

View file

@ -1,2 +0,0 @@
require("lsp").setup "html"
require("lsp").setup "tailwindcss"

View file

@ -1 +0,0 @@
require("lsp").setup "java"

View file

@ -1 +0,0 @@
require("lsp").setup "javascript"

View file

@ -1,2 +0,0 @@
require("lsp").setup "javascriptreact"
require("lsp").setup "tailwindcss"

View file

@ -1 +0,0 @@
require("lsp").setup "json"

View file

@ -1 +0,0 @@
require("lsp").setup "julia"

View file

@ -1 +0,0 @@
require("lsp").setup "kotlin"

View file

@ -1 +0,0 @@
css.lua

View file

@ -1 +0,0 @@
require("lsp").setup "lua"

View file

@ -1,2 +0,0 @@
vim.cmd [[nmap <buffer> h -]]
vim.cmd [[nmap <buffer> l <cr>]]

View file

@ -1 +0,0 @@
require("lsp").setup "nix"

View file

@ -1 +0,0 @@
require("lsp").setup "perl"

View file

@ -1 +0,0 @@
require("lsp").setup "php"

View file

@ -1,3 +0,0 @@
require("lsp").setup "ps1"
vim.cmd [[setlocal ts=4 sw=4]]

View file

@ -1 +0,0 @@
require("lsp").setup "puppet"

View file

@ -1,3 +0,0 @@
require("lsp").setup "python"
-- TODO get from dap
-- require("lang.python").dap()

View file

@ -1,2 +0,0 @@
-- R -e 'install.packages("languageserver",repos = "http://cran.us.r-project.org")'
require("lsp").setup "r"

View file

@ -1 +0,0 @@
r.lua

View file

@ -1,2 +0,0 @@
-- also support sorbet
require("lsp").setup "ruby"

View file

@ -1,4 +0,0 @@
require("lsp").setup "rust"
-- TODO get from dap
-- require("lang.rust").dap()

View file

@ -1 +0,0 @@
css.lua

View file

@ -1 +0,0 @@
scala.lua

View file

@ -1 +0,0 @@
require("lsp").setup "scala"

View file

@ -1 +0,0 @@
css.lua

View file

@ -1 +0,0 @@
require("lsp").setup "sh"

View file

@ -1 +0,0 @@
require("lsp").setup "solidity"

View file

@ -1 +0,0 @@
require("lsp").setup "sql"

View file

@ -1,2 +0,0 @@
require("lsp").setup "svelte"
require("lsp").setup "tailwindcss"

View file

@ -1 +0,0 @@
require("lsp").setup "swift"

View file

@ -1 +0,0 @@
require("lsp").setup "terraform"

View file

@ -1 +0,0 @@
require("lsp").setup "tex"

View file

View file

@ -1 +0,0 @@
vim.cmd [[setlocal commentstring=#%s]]

View file

@ -1 +0,0 @@
require("lsp").setup "typescript"

View file

@ -1,2 +0,0 @@
require("lsp").setup "typescript"
require("lsp").setup "tailwindcss"

View file

@ -1 +0,0 @@
require("lsp").setup "vim"

View file

@ -1,2 +0,0 @@
require("lsp").setup "vue"
require("lsp").setup "tailwindcss"

View file

@ -1 +0,0 @@
require("lsp").setup "yaml"

View file

@ -1 +0,0 @@
require("lsp").setup "zig"

View file

@ -1 +0,0 @@
require("lsp").setup "sh"

View file

@ -18,10 +18,9 @@ Log:debug "Starting LunarVim"
vim.g.colors_name = lvim.colorscheme -- Colorscheme must get called after plugins are loaded or it will break new installs. vim.g.colors_name = lvim.colorscheme -- Colorscheme must get called after plugins are loaded or it will break new installs.
vim.cmd("colorscheme " .. lvim.colorscheme) vim.cmd("colorscheme " .. lvim.colorscheme)
require("utils").toggle_autoformat()
local commands = require "core.commands" local commands = require "core.commands"
commands.load(commands.defaults) commands.load(commands.defaults)
require("lsp").global_setup()
require("keymappings").setup() require("keymappings").setup()
require("lsp").setup()

View file

@ -85,9 +85,10 @@ function M:init()
vim.cmd("set spellfile=" .. join_paths(self.config_dir, "spell", "en.utf-8.add")) vim.cmd("set spellfile=" .. join_paths(self.config_dir, "spell", "en.utf-8.add"))
end end
vim.fn.mkdir(vim.fn.stdpath "cache", "p")
-- FIXME: currently unreliable in unit-tests -- FIXME: currently unreliable in unit-tests
if not os.getenv "LVIM_TEST_ENV" then if not os.getenv "LVIM_TEST_ENV" then
vim.fn.mkdir(vim.fn.stdpath "cache", "p")
require("impatient").setup { require("impatient").setup {
path = vim.fn.stdpath "cache" .. "/lvim_cache", path = vim.fn.stdpath "cache" .. "/lvim_cache",
enable_profiling = true, enable_profiling = true,
@ -112,6 +113,7 @@ end
function M:update() function M:update()
M:update_repo() M:update_repo()
M:reset_cache() M:reset_cache()
require("lsp.templates").generate_templates()
vim.schedule(function() vim.schedule(function()
-- TODO: add a changelog -- TODO: add a changelog
vim.notify("Update complete", vim.log.levels.INFO) vim.notify("Update complete", vim.log.levels.INFO)

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,106 @@ function M:init(opts)
local settings = require "config.settings" local settings = require "config.settings"
settings.load_options() settings.load_options()
local lvim_lsp_config = require "lsp.config"
lvim.lsp = vim.deepcopy(lvim_lsp_config)
local supported_languages = {
"asm",
"bash",
"beancount",
"bibtex",
"bicep",
"c",
"c_sharp",
"clojure",
"cmake",
"comment",
"commonlisp",
"cpp",
"crystal",
"cs",
"css",
"cuda",
"d",
"dart",
"dockerfile",
"dot",
"elixir",
"elm",
"emmet",
"erlang",
"fennel",
"fish",
"fortran",
"gdscript",
"glimmer",
"go",
"gomod",
"graphql",
"haskell",
"hcl",
"heex",
"html",
"java",
"javascript",
"javascriptreact",
"jsdoc",
"json",
"json5",
"jsonc",
"julia",
"kotlin",
"latex",
"ledger",
"less",
"lua",
"markdown",
"nginx",
"nix",
"ocaml",
"ocaml_interface",
"perl",
"php",
"pioasm",
"ps1",
"puppet",
"python",
"ql",
"query",
"r",
"regex",
"rst",
"ruby",
"rust",
"scala",
"scss",
"sh",
"solidity",
"sparql",
"sql",
"supercollider",
"surface",
"svelte",
"swift",
"tailwindcss",
"terraform",
"tex",
"tlaplus",
"toml",
"tsx",
"turtle",
"typescript",
"typescriptreact",
"verilog",
"vim",
"vue",
"yaml",
"yang",
"zig",
}
require("lsp.manager").init_defaults(supported_languages)
end end
--- Override the configuration with a user provided one --- Override the configuration with a user provided one

View file

@ -15,7 +15,6 @@ local builtins = {
"core.bufferline", "core.bufferline",
"core.autopairs", "core.autopairs",
"core.comment", "core.comment",
"core.lspinstall",
"core.lualine", "core.lualine",
} }

View file

@ -35,9 +35,35 @@ M.config = function()
select = true, select = true,
}, },
formatting = { formatting = {
kind_icons = {
Class = "",
Color = "",
Constant = "",
Constructor = "",
Enum = "",
EnumMember = "",
Event = "",
Field = "",
File = "",
Folder = "",
Function = "",
Interface = "",
Keyword = "",
Method = "",
Module = "",
Operator = "",
Property = "",
Reference = "",
Snippet = "",
Struct = "",
Text = "",
TypeParameter = "",
Unit = "",
Value = "",
Variable = "",
},
format = function(entry, vim_item) format = function(entry, vim_item)
local icons = require("lsp.kind").icons vim_item.kind = lvim.builtin.cmp.formatting.kind_icons[vim_item.kind]
vim_item.kind = icons[vim_item.kind]
vim_item.menu = ({ vim_item.menu = ({
nvim_lsp = "(LSP)", nvim_lsp = "(LSP)",
emoji = "(Emoji)", emoji = "(Emoji)",

View file

@ -10,6 +10,7 @@ local M = {
} }
local fmt = string.format local fmt = string.format
local text = require "interface.text"
local function str_list(list) local function str_list(list)
return fmt("[ %s ]", table.concat(list, ", ")) return fmt("[ %s ]", table.concat(list, ", "))
@ -65,32 +66,14 @@ local function tbl_set_highlight(terms, highlight_group)
end end
end end
function M.toggle_popup(ft) local function make_client_info(client)
local lsp_utils = require "lsp.utils" local client_enabled_caps = require("lsp.utils").get_ls_capabilities(client.id)
local client = lsp_utils.get_active_client_by_ft(ft) local name = client.name
local is_client_active = false local id = client.id
local client_enabled_caps = {} local document_formatting = client.resolved_capabilities.document_formatting
local client_name = "" local client_info = {
local client_id = 0 fmt("* Name: %s", name),
local document_formatting = false fmt("* Id: %s", tostring(id)),
if client ~= nil then
is_client_active = not client.is_stopped()
client_enabled_caps = require("lsp").get_ls_capabilities(client.id)
client_name = client.name
client_id = client.id
document_formatting = client.resolved_capabilities.document_formatting
end
local header = {
fmt("Detected filetype: %s", ft),
fmt("Treesitter active: %s", tostring(next(vim.treesitter.highlighter.active) ~= nil)),
}
local text = require "interface.text"
local lsp_info = {
"Language Server Protocol (LSP) info",
fmt("* Associated server: %s", client_name),
fmt("* Active: %s (id: %d)", tostring(is_client_active), client_id),
fmt("* Supports formatting: %s", tostring(document_formatting)), fmt("* Supports formatting: %s", tostring(document_formatting)),
} }
if not vim.tbl_isempty(client_enabled_caps) then if not vim.tbl_isempty(client_enabled_caps) then
@ -99,10 +82,39 @@ function M.toggle_popup(ft)
local enabled_caps = text.format_table(client_enabled_caps, 3, " | ") local enabled_caps = text.format_table(client_enabled_caps, 3, " | ")
enabled_caps = text.shift_right(enabled_caps, caps_text_len) enabled_caps = text.shift_right(enabled_caps, caps_text_len)
enabled_caps[1] = fmt("%s%s", caps_text, enabled_caps[1]:sub(caps_text_len + 1)) enabled_caps[1] = fmt("%s%s", caps_text, enabled_caps[1]:sub(caps_text_len + 1))
vim.list_extend(lsp_info, enabled_caps) vim.list_extend(client_info, enabled_caps)
end end
local null_ls = require "lsp.null-ls"
local registered_providers = null_ls.list_supported_provider_names(ft) return client_info
end
function M.toggle_popup(ft)
local lsp_utils = require "lsp.utils"
local clients = lsp_utils.get_active_client_by_ft(ft)
local client_names = {}
local header = {
fmt("Detected filetype: %s", ft),
fmt("Treesitter active: %s", tostring(next(vim.treesitter.highlighter.active) ~= nil)),
}
local lsp_info = {
"Language Server Protocol (LSP) info",
fmt "* Associated server(s):",
}
for _, client in pairs(clients) do
vim.list_extend(lsp_info, make_client_info(client))
table.insert(client_names, client.name)
end
local null_formatters = require "lsp.null-ls.formatters"
local null_linters = require "lsp.null-ls.linters"
local registered_formatters = null_formatters.list_supported_names(ft)
local registered_linters = null_linters.list_supported_names(ft)
local registered_providers = {}
vim.list_extend(registered_providers, registered_formatters)
vim.list_extend(registered_providers, registered_linters)
local registered_count = vim.tbl_count(registered_providers) local registered_count = vim.tbl_count(registered_providers)
local null_ls_info = { local null_ls_info = {
"Formatters and linters", "Formatters and linters",
@ -113,24 +125,6 @@ function M.toggle_popup(ft)
), ),
} }
local null_formatters = require "lsp.null-ls.formatters"
local missing_formatters = null_formatters.list_unsupported_names(ft)
local missing_formatters_status = {}
if not vim.tbl_isempty(missing_formatters) then
missing_formatters_status = {
fmt("* Missing formatters: %s", table.concat(missing_formatters, "  , ") .. ""),
}
end
local null_linters = require "lsp.null-ls.linters"
local missing_linters = null_linters.list_unsupported_names(ft)
local missing_linters_status = {}
if not vim.tbl_isempty(missing_linters) then
missing_linters_status = {
fmt("* Missing linters: %s", table.concat(missing_linters, "  , ") .. ""),
}
end
local content_provider = function(popup) local content_provider = function(popup)
local content = {} local content = {}
@ -143,8 +137,6 @@ function M.toggle_popup(ft)
lsp_info, lsp_info,
{ "" }, { "" },
null_ls_info, null_ls_info,
missing_formatters_status,
missing_linters_status,
{ "" }, { "" },
{ "" }, { "" },
get_formatter_suggestion_msg(ft), get_formatter_suggestion_msg(ft),
@ -167,11 +159,8 @@ function M.toggle_popup(ft)
vim.cmd 'let m=matchadd("string", "true")' vim.cmd 'let m=matchadd("string", "true")'
vim.cmd 'let m=matchadd("error", "false")' vim.cmd 'let m=matchadd("error", "false")'
tbl_set_highlight(registered_providers, "LvimInfoIdentifier") tbl_set_highlight(registered_providers, "LvimInfoIdentifier")
tbl_set_highlight(missing_formatters, "LvimInfoIdentifier")
tbl_set_highlight(missing_linters, "LvimInfoIdentifier")
-- tbl_set_highlight(require("lsp.null-ls.formatters").list_available(ft), "LvimInfoIdentifier") -- tbl_set_highlight(require("lsp.null-ls.formatters").list_available(ft), "LvimInfoIdentifier")
-- tbl_set_highlight(require("lsp.null-ls.linters").list_available(ft), "LvimInfoIdentifier") -- tbl_set_highlight(require("lsp.null-ls.linters").list_available(ft), "LvimInfoIdentifier")
vim.cmd('let m=matchadd("LvimInfoIdentifier", "' .. client_name .. '")')
end end
local Popup = require("interface.popup"):new { local Popup = require("interface.popup"):new {

View file

@ -8,6 +8,7 @@ function Log:add_entry(msg, level)
if self.__handle then if self.__handle then
-- plenary uses lower-case log levels -- plenary uses lower-case log levels
self.__handle[level:lower()](msg) self.__handle[level:lower()](msg)
return
end end
local status_ok, plenary = pcall(require, "plenary") local status_ok, plenary = pcall(require, "plenary")
if status_ok then if status_ok then

View file

@ -1,19 +0,0 @@
local M = {}
M.config = function()
lvim.builtin.lspinstall = {
active = true,
on_config_done = nil,
}
end
M.setup = function()
local lspinstall = require "lspinstall"
lspinstall.setup()
if lvim.builtin.lspinstall.on_config_done then
lvim.builtin.lspinstall.on_config_done(lspinstall)
end
end
return M

View file

@ -96,14 +96,11 @@ return {
local buf_client_names = {} local buf_client_names = {}
-- add client -- add client
local utils = require "lsp.utils"
local active_client = utils.get_active_client_by_ft(buf_ft)
for _, client in pairs(buf_clients) do for _, client in pairs(buf_clients) do
if client.name ~= "null-ls" then if client.name ~= "null-ls" then
table.insert(buf_client_names, client.name) table.insert(buf_client_names, client.name)
end end
end end
vim.list_extend(buf_client_names, active_client or {})
-- add formatter -- add formatter
local formatters = require "lsp.null-ls.formatters" local formatters = require "lsp.null-ls.formatters"

View file

@ -148,9 +148,9 @@ M.config = function()
"<cmd>Telescope lsp_workspace_diagnostics<cr>", "<cmd>Telescope lsp_workspace_diagnostics<cr>",
"Workspace Diagnostics", "Workspace Diagnostics",
}, },
-- f = { "<cmd>silent FormatWrite<cr>", "Format" },
f = { "<cmd>lua vim.lsp.buf.formatting()<cr>", "Format" }, f = { "<cmd>lua vim.lsp.buf.formatting()<cr>", "Format" },
i = { "<cmd>LspInfo<cr>", "Info" }, i = { "<cmd>LspInfo<cr>", "Info" },
I = { "<cmd>LspInstallInfo<cr>", "Installer Info" },
j = { j = {
"<cmd>lua vim.lsp.diagnostic.goto_next({popup_opts = {border = lvim.lsp.popup_border}})<cr>", "<cmd>lua vim.lsp.diagnostic.goto_next({popup_opts = {border = lvim.lsp.popup_border}})<cr>",
"Next Diagnostic", "Next Diagnostic",

27
lua/lsp/config.lua Normal file
View file

@ -0,0 +1,27 @@
return {
templates_dir = join_paths(get_runtime_dir(), "site", "after", "ftplugin"),
diagnostics = {
signs = {
active = true,
values = {
{ name = "LspDiagnosticsSignError", text = "" },
{ name = "LspDiagnosticsSignWarning", text = "" },
{ name = "LspDiagnosticsSignHint", text = "" },
{ name = "LspDiagnosticsSignInformation", text = "" },
},
},
virtual_text = {
prefix = "",
spacing = 0,
},
update_in_insert = false,
underline = true,
severity_sort = true,
},
override = {},
document_highlight = true,
popup_border = "single",
on_attach_callback = nil,
on_init_callback = nil,
automatic_servers_installation = true,
}

View file

@ -1,5 +1,6 @@
local M = {} local M = {}
local Log = require "core.log" local Log = require "core.log"
local utils = require "utils"
local function lsp_highlight_document(client) local function lsp_highlight_document(client)
if lvim.lsp.document_highlight == false then if lvim.lsp.document_highlight == false then
@ -61,48 +62,12 @@ function M.common_capabilities()
return capabilities return capabilities
end end
function M.get_ls_capabilities(client_id)
local client
if not client_id then
local buf_clients = vim.lsp.buf_get_clients()
for _, buf_client in ipairs(buf_clients) do
if buf_client.name ~= "null-ls" then
client_id = buf_client.id
break
end
end
end
if not client_id then
error "Unable to determine client_id"
end
client = vim.lsp.get_client_by_id(tonumber(client_id))
local enabled_caps = {}
for k, v in pairs(client.resolved_capabilities) do
if v == true then
table.insert(enabled_caps, k)
end
end
return enabled_caps
end
function M.common_on_init(client, bufnr) function M.common_on_init(client, bufnr)
if lvim.lsp.on_init_callback then if lvim.lsp.on_init_callback then
lvim.lsp.on_init_callback(client, bufnr) lvim.lsp.on_init_callback(client, bufnr)
Log:debug "Called lsp.on_init_callback" Log:debug "Called lsp.on_init_callback"
return return
end end
local formatters = lvim.lang[vim.bo.filetype].formatters
if not vim.tbl_isempty(formatters) and formatters[1]["exe"] ~= nil and formatters[1].exe ~= "" then
client.resolved_capabilities.document_formatting = false
Log:debug(
string.format("Overriding language server [%s] with format provider [%s]", client.name, formatters[1].exe)
)
end
end end
function M.common_on_attach(client, bufnr) function M.common_on_attach(client, bufnr)
@ -112,63 +77,46 @@ function M.common_on_attach(client, bufnr)
end end
lsp_highlight_document(client) lsp_highlight_document(client)
add_lsp_buffer_keybindings(bufnr) add_lsp_buffer_keybindings(bufnr)
require("lsp.null-ls").setup(vim.bo.filetype)
end end
function M.setup(lang) local function bootstrap_nlsp(opts)
local lsp_utils = require "lsp.utils" opts = opts or {}
local lsp = lvim.lang[lang].lsp local lsp_settings_status_ok, lsp_settings = pcall(require, "nlspsettings")
if (lsp.active ~= nil and not lsp.active) or lsp_utils.is_client_active(lsp.provider) then if lsp_settings_status_ok then
lsp_settings.setup(opts)
end
end
function M.get_common_opts()
return {
on_attach = M.common_on_attach,
on_init = M.common_on_init,
capabilities = M.common_capabilities(),
}
end
function M.setup()
Log:debug "Setting up LSP support"
local lsp_status_ok, _ = pcall(require, "lspconfig")
if not lsp_status_ok then
return return
end end
local overrides = lvim.lsp.override
if type(overrides) == "table" then
if vim.tbl_contains(overrides, lang) then
return
end
end
if lsp.provider ~= nil and lsp.provider ~= "" then
local lspconfig = require "lspconfig"
if not lsp.setup.on_attach then
lsp.setup.on_attach = M.common_on_attach
end
if not lsp.setup.on_init then
lsp.setup.on_init = M.common_on_init
end
if not lsp.setup.capabilities then
lsp.setup.capabilities = M.common_capabilities()
end
lspconfig[lsp.provider].setup(lsp.setup)
end
end
function M.global_setup()
vim.lsp.protocol.CompletionItemKind = lvim.lsp.completion.item_kind
for _, sign in ipairs(lvim.lsp.diagnostics.signs.values) do for _, sign in ipairs(lvim.lsp.diagnostics.signs.values) do
vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = sign.name }) vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = sign.name })
end end
require("lsp.handlers").setup() require("lsp.handlers").setup()
local null_status_ok, null_ls = pcall(require, "null-ls") if not utils.is_directory(lvim.lsp.templates_dir) then
if null_status_ok then require("lsp.templates").generate_templates()
null_ls.config()
require("lspconfig")["null-ls"].setup(lvim.lsp.null_ls.setup)
end end
local utils = require "utils" bootstrap_nlsp { config_home = utils.join_paths(get_config_dir(), "lsp-settings") }
local lsp_settings_status_ok, lsp_settings = pcall(require, "nlspsettings") require("lsp.null-ls").setup()
if lsp_settings_status_ok then
lsp_settings.setup { require("utils").toggle_autoformat()
config_home = utils.join_paths(get_config_dir(), "lsp-settings"),
}
end
end end
return M return M

View file

@ -1,31 +0,0 @@
local M = {}
M.icons = {
Class = "",
Color = "",
Constant = "",
Constructor = "",
Enum = "",
EnumMember = "",
Event = "",
Field = "",
File = "",
Folder = "",
Function = "",
Interface = "",
Keyword = "",
Method = "",
Module = "",
Operator = "",
Property = "",
Reference = "",
Snippet = "",
Struct = "",
Text = "",
TypeParameter = "",
Unit = "",
Value = "",
Variable = "",
}
return M

82
lua/lsp/manager.lua Normal file
View file

@ -0,0 +1,82 @@
local M = {}
local Log = require "core.log"
local lsp_utils = require "lsp.utils"
function M.init_defaults(languages)
for _, entry in ipairs(languages) do
if not lvim.lang[entry] then
lvim.lang[entry] = {
formatters = {},
linters = {},
}
end
end
end
local function is_overridden(server)
local overrides = lvim.lsp.override
if type(overrides) == "table" then
if vim.tbl_contains(overrides, server) then
return
end
end
end
function M.setup_server(server_name)
vim.validate {
name = { server_name, "string" },
}
if lsp_utils.is_client_active(server_name) or is_overridden(server_name) then
return
end
local lsp_installer_servers = require "nvim-lsp-installer.servers"
local server_available, requested_server = lsp_installer_servers.get_server(server_name)
if server_available then
if not requested_server:is_installed() then
Log:debug(string.format("[%s] is not installed", server_name))
if lvim.lsp.automatic_servers_installation then
Log:debug(string.format("Installing [%s]", server_name))
requested_server:install()
else
return
end
end
end
local default_config = {
on_attach = require("lsp").common_on_attach,
on_init = require("lsp").common_on_init,
capabilities = require("lsp").common_capabilities(),
}
local status_ok, custom_config = pcall(require, "lsp/providers/" .. requested_server.name)
if status_ok then
local new_config = vim.tbl_deep_extend("force", default_config, custom_config)
Log:debug("Using custom configuration for requested server: " .. requested_server.name)
requested_server:setup(new_config)
else
Log:debug("Using the default configuration for requested server: " .. requested_server.name)
requested_server:setup(default_config)
end
end
function M.setup(servers)
local status_ok, _ = pcall(require, "nvim-lsp-installer")
if not status_ok then
return
end
--- allow using a single value
if type(servers) == "string" then
servers = { servers }
end
for _, server in ipairs(servers) do
M.setup_server(server)
end
end
return M

View file

@ -1,29 +1,14 @@
local M = {} local M = {}
local formatters_by_ft = {}
local null_ls = require "null-ls" local null_ls = require "null-ls"
local services = require "lsp.null-ls.services" local services = require "lsp.null-ls.services"
local Log = require "core.log" local Log = require "core.log"
local function list_names(formatters, options)
options = options or {}
local filter = options.filter or "supported"
return vim.tbl_keys(formatters[filter])
end
function M.list_supported_names(filetype) function M.list_supported_names(filetype)
if not formatters_by_ft[filetype] then local null_ls_methods = require "null-ls.methods"
return {} local formatter_method = null_ls_methods.internal["FORMATTING"]
end local registered_providers = services.list_registered_providers_names(filetype)
return list_names(formatters_by_ft[filetype], { filter = "supported" }) return registered_providers[formatter_method] or {}
end
function M.list_unsupported_names(filetype)
if not formatters_by_ft[filetype] then
return {}
end
return list_names(formatters_by_ft[filetype], { filter = "unsupported" })
end end
function M.list_available(filetype) function M.list_available(filetype)
@ -62,12 +47,13 @@ function M.list_configured(formatter_configs)
return { supported = formatters, unsupported = errors } return { supported = formatters, unsupported = errors }
end end
function M.setup(filetype, options) function M.setup(formatter_configs, filetype)
if not lvim.lang[filetype] or (formatters_by_ft[filetype] and not options.force_reload) then if vim.tbl_isempty(formatter_configs) then
return return
end end
formatters_by_ft[filetype] = M.list_configured(lvim.lang[filetype].formatters) local formatters_by_ft = {}
formatters_by_ft[filetype] = M.list_configured(formatter_configs)
null_ls.register { sources = formatters_by_ft[filetype].supported } null_ls.register { sources = formatters_by_ft[filetype].supported }
end end

View file

@ -1,44 +1,26 @@
local M = {} local M = {}
function M.list_supported_provider_names(filetype) local Log = require "core.log"
local names = {}
local formatters = require "lsp.null-ls.formatters" local formatters = require "lsp.null-ls.formatters"
local linters = require "lsp.null-ls.linters" local linters = require "lsp.null-ls.linters"
vim.list_extend(names, formatters.list_supported_names(filetype)) function M:setup()
vim.list_extend(names, linters.list_supported_names(filetype)) local status_ok, null_ls = pcall(require, "null-ls")
if not status_ok then
return names Log:error "Missing null-ls dependency"
end
function M.list_unsupported_provider_names(filetype)
local names = {}
local formatters = require "lsp.null-ls.formatters"
local linters = require "lsp.null-ls.linters"
vim.list_extend(names, formatters.list_unsupported_names(filetype))
vim.list_extend(names, linters.list_unsupported_names(filetype))
return names
end
-- TODO: for linters and formatters with spaces and '-' replace with '_'
function M.setup(filetype, options)
options = options or {}
local ok, _ = pcall(require, "null-ls")
if not ok then
require("core.log"):error "Missing null-ls dependency"
return return
end end
local formatters = require "lsp.null-ls.formatters" null_ls.config()
local linters = require "lsp.null-ls.linters" require("lspconfig")["null-ls"].setup {}
for _, filetype in pairs(lvim.lang) do
formatters.setup(filetype, options) if filetype.formatters then
linters.setup(filetype, options) formatters.setup(filetype.formatters, filetype)
end
if filetype.linters then
linters.setup(filetype.linters, filetype)
end
end
end end
return M return M

View file

@ -1,29 +1,14 @@
local M = {} local M = {}
local linters_by_ft = {}
local null_ls = require "null-ls" local null_ls = require "null-ls"
local services = require "lsp.null-ls.services" local services = require "lsp.null-ls.services"
local Log = require "core.log" local Log = require "core.log"
local function list_names(linters, options)
options = options or {}
local filter = options.filter or "supported"
return vim.tbl_keys(linters[filter])
end
function M.list_supported_names(filetype) function M.list_supported_names(filetype)
if not linters_by_ft[filetype] then local null_ls_methods = require "null-ls.methods"
return {} local linter_method = null_ls_methods.internal["DIAGNOSTICS"]
end local registered_providers = services.list_registered_providers_names(filetype)
return list_names(linters_by_ft[filetype], { filter = "supported" }) return registered_providers[linter_method] or {}
end
function M.list_unsupported_names(filetype)
if not linters_by_ft[filetype] then
return {}
end
return list_names(linters_by_ft[filetype], { filter = "unsupported" })
end end
function M.list_available(filetype) function M.list_available(filetype)
@ -62,12 +47,13 @@ function M.list_configured(linter_configs)
return { supported = linters, unsupported = errors } return { supported = linters, unsupported = errors }
end end
function M.setup(filetype, options) function M.setup(linter_configs, filetype)
if not lvim.lang[filetype] or (linters_by_ft[filetype] and not options.force_reload) then if vim.tbl_isempty(linter_configs) then
return return
end end
linters_by_ft[filetype] = M.list_configured(lvim.lang[filetype].linters) local linters_by_ft = {}
linters_by_ft[filetype] = M.list_configured(linter_configs)
null_ls.register { sources = linters_by_ft[filetype].supported } null_ls.register { sources = linters_by_ft[filetype].supported }
end end

View file

@ -45,4 +45,19 @@ function M.find_command(command)
return nil return nil
end end
function M.list_registered_providers_names(filetype)
local u = require "null-ls.utils"
local c = require "null-ls.config"
local registered = {}
for method, source in pairs(c.get()._methods) do
for name, filetypes in pairs(source) do
if u.filetype_matches(filetypes, filetype) then
registered[method] = registered[method] or {}
table.insert(registered[method], name)
end
end
end
return registered
end
return M return M

View file

@ -0,0 +1,30 @@
local schemas = nil
local status_ok, jsonls_settings = pcall(require, "nlspsettings.jsonls")
if status_ok then
schemas = jsonls_settings.get_default_schemas()
end
local opts = {
setup = {
settings = {
json = {
schemas = schemas,
-- = {
-- {
-- fileMatch = { "package.json" },
-- url = "https://json.schemastore.org/package.json",
-- },
-- },
},
},
commands = {
Format = {
function()
vim.lsp.buf.range_formatting({}, { 0, 0 }, { vim.fn.line "$", 0 })
end,
},
},
},
}
return opts

View file

@ -0,0 +1,19 @@
local opts = {
settings = {
Lua = {
diagnostics = {
globals = { "vim", "lvim" },
},
workspace = {
library = {
[require("utils").join_paths(get_runtime_dir(), "lvim", "lua")] = true,
[vim.fn.expand "$VIMRUNTIME/lua"] = true,
[vim.fn.expand "$VIMRUNTIME/lua/vim/lsp"] = true,
},
maxPreload = 100000,
preloadFileSize = 10000,
},
},
},
}
return opts

View file

@ -0,0 +1,26 @@
local opts = {
setup = {
root_dir = function(fname)
local util = require "lspconfig/util"
return util.root_pattern "package.json"(fname) or util.root_pattern "vue.config.js"(fname) or vim.fn.getcwd()
end,
init_options = {
config = {
vetur = {
completion = {
autoImport = true,
tagCasing = "kebab",
useScaffoldSnippets = true,
},
useWorkspaceDependencies = true,
validation = {
script = true,
style = true,
template = true,
},
},
},
},
},
}
return opts

98
lua/lsp/templates.lua Normal file
View file

@ -0,0 +1,98 @@
local M = {}
local Log = require "core.log"
local utils = require "utils"
local get_supported_filetypes = require("lsp.utils").get_supported_filetypes
local ftplugin_dir = lvim.lsp.templates_dir
local join_paths = _G.join_paths
function M.remove_template_files()
-- remove any outdated files
for _, file in ipairs(vim.fn.glob(ftplugin_dir .. "/*.lua", 1, 1)) do
vim.fn.delete(file)
end
end
---Checks if a server is ignored by default because of a conflict
---Only TSServer is enabled by default for the javascript-family
---@param server_name string
function M.is_ignored(server_name, filetypes)
--TODO: this is easy to be made configurable once stable
filetypes = filetypes or get_supported_filetypes(server_name)
if vim.tbl_contains(filetypes, "javascript") then
if server_name == "tsserver" or server_name == "tailwindcss" then
return false
else
return true
end
end
local blacklist = {
"jedi_language_server",
"pylsp",
"sqlls",
"sqls",
"angularls",
"ansiblels",
}
return vim.tbl_contains(blacklist, server_name)
end
---Generates an ftplugin file based on the server_name in the selected directory
---@param server_name string name of a valid language server, e.g. pyright, gopls, tsserver, etc.
---@param dir string the full path to the desired directory
function M.generate_ftplugin(server_name, dir)
-- we need to go through lspconfig to get the corresponding filetypes currently
local filetypes = get_supported_filetypes(server_name) or {}
if not filetypes then
return
end
if M.is_ignored(server_name, filetypes) then
return
end
-- print("got associated filetypes: " .. vim.inspect(filetypes))
for _, filetype in ipairs(filetypes) do
local filename = join_paths(dir, filetype .. ".lua")
local setup_cmd = string.format([[require("lsp.manager").setup(%q)]], server_name)
-- print("using setup_cmd: " .. setup_cmd)
-- overwrite the file completely
utils.write_file(filename, setup_cmd .. "\n", "a")
end
end
---Generates ftplugin files based on a list of server_names
---The files are generated to a runtimepath: "$LUNARVIM_RUNTIME_DIR/site/after/ftplugin/template.lua"
---@param servers_names table list of servers to be enabled. Will add all by default
function M.generate_templates(servers_names)
servers_names = servers_names or {}
Log:debug "Templates installation in progress"
M.remove_template_files()
if vim.tbl_isempty(servers_names) then
local available_servers = require("nvim-lsp-installer.servers").get_available_servers()
for _, server in pairs(available_servers) do
table.insert(servers_names, server.name)
end
end
-- create the directory if it didn't exist
if not utils.is_directory(lvim.lsp.templates_dir) then
vim.fn.mkdir(ftplugin_dir, "p")
end
for _, server in ipairs(servers_names) do
M.generate_ftplugin(server, ftplugin_dir)
end
Log:debug "Templates installation is complete"
end
return M

View file

@ -10,19 +10,60 @@ function M.is_client_active(name)
return false return false
end end
-- FIXME: this should return a list instead function M.disable_formatting_capability(client)
function M.get_active_client_by_ft(filetype) -- FIXME: figure out a reasonable way to do this
if not lvim.lang[filetype] or not lvim.lang[filetype].lsp then client.resolved_capabilities.document_formatting = false
return nil require("core.log"):debug(string.format("Turning off formatting capability for language server [%s] ", client.name))
end end
function M.get_active_client_by_ft(filetype)
local matches = {}
local clients = vim.lsp.get_active_clients() local clients = vim.lsp.get_active_clients()
for _, client in pairs(clients) do for _, client in pairs(clients) do
if client.name == lvim.lang[filetype].lsp.provider then local supported_filetypes = client.config.filetypes or {}
return client if client.name ~= "null-ls" and vim.tbl_contains(supported_filetypes, filetype) then
table.insert(matches, client)
end
end
return matches
end
function M.get_ls_capabilities(client_id)
if not client_id then
local buf_clients = vim.lsp.buf_get_clients()
for _, buf_client in ipairs(buf_clients) do
if buf_client.name ~= "null-ls" then
client_id = buf_client.id
break
end
end
end
if not client_id then
error "Unable to determine client_id"
return
end
local client = vim.lsp.get_client_by_id(tonumber(client_id))
local enabled_caps = {}
for capability, status in pairs(client.resolved_capabilities) do
if status == true then
table.insert(enabled_caps, capability)
end
end
return enabled_caps
end
function M.get_supported_filetypes(server_name)
-- print("got filetypes query request for: " .. server_name)
local configs = require "lspconfig/configs"
pcall(require, ("lspconfig/" .. server_name))
for _, config in pairs(configs) do
if config.name == server_name then
return config.document_config.default_config.filetypes or {}
end end
end end
return nil
end end
return M return M

View file

@ -6,12 +6,7 @@ return {
{ "jose-elias-alvarez/null-ls.nvim" }, { "jose-elias-alvarez/null-ls.nvim" },
{ "antoinemadec/FixCursorHold.nvim" }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open { "antoinemadec/FixCursorHold.nvim" }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open
{ {
"kabouzeid/nvim-lspinstall", "williamboman/nvim-lsp-installer",
event = "VimEnter",
config = function()
local lspinstall = require "core.lspinstall"
lspinstall.setup()
end,
}, },
{ "nvim-lua/popup.nvim" }, { "nvim-lua/popup.nvim" },

View file

@ -99,8 +99,7 @@ function utils.reload_lv_config()
vim.cmd ":PackerInstall" vim.cmd ":PackerInstall"
vim.cmd ":PackerCompile" vim.cmd ":PackerCompile"
-- vim.cmd ":PackerClean" -- vim.cmd ":PackerClean"
local null_ls = require "lsp.null-ls" require("lsp").setup()
null_ls.setup(vim.bo.filetype, { force_reload = true })
Log:info "Reloaded configuration" Log:info "Reloaded configuration"
end end
@ -133,15 +132,106 @@ function utils.apply_defaults(config, default_config)
end end
--- Checks whether a given path exists and is a file. --- Checks whether a given path exists and is a file.
--@param filename (string) path to check --@param path (string) path to check
--@returns (bool) --@returns (bool)
function utils.is_file(filename) function utils.is_file(path)
local stat = uv.fs_stat(filename) local stat = uv.fs_stat(path)
return stat and stat.type == "file" or false return stat and stat.type == "file" or false
end end
--- Checks whether a given path exists and is a directory
--@param path (string) path to check
--@returns (bool)
function utils.is_directory(path)
local stat = uv.fs_stat(path)
return stat and stat.type == "directory" or false
end
function utils.write_file(path, txt, flag)
uv.fs_open(path, flag, 438, function(open_err, fd)
assert(not open_err, open_err)
uv.fs_write(fd, txt, -1, function(write_err)
assert(not write_err, write_err)
uv.fs_close(fd, function(close_err)
assert(not close_err, close_err)
end)
end)
end)
end
utils.join_paths = _G.join_paths utils.join_paths = _G.join_paths
function utils.write_file(path, txt, flag)
uv.fs_open(path, flag, 438, function(open_err, fd)
assert(not open_err, open_err)
uv.fs_write(fd, txt, -1, function(write_err)
assert(not write_err, write_err)
uv.fs_close(fd, function(close_err)
assert(not close_err, close_err)
end)
end)
end)
end
function utils.debounce(ms, fn)
local timer = vim.loop.new_timer()
return function(...)
local argv = { ... }
timer:start(ms, 0, function()
timer:stop()
vim.schedule_wrap(fn)(unpack(argv))
end)
end
end
function utils.search_file(file, args)
local Job = require "plenary.job"
local stderr = {}
local stdout, ret = Job
:new({
command = "grep",
args = { args, file },
cwd = get_cache_dir(),
on_stderr = function(_, data)
table.insert(stderr, data)
end,
})
:sync()
return stdout, ret, stderr
end
function utils.file_contains(file, query)
local stdout, ret, stderr = utils.search_file(file, query)
if ret == 0 then
return true
end
if not vim.tbl_isempty(stderr) then
error(vim.inspect(stderr))
end
if not vim.tbl_isempty(stdout) then
error(vim.inspect(stdout))
end
return false
end
function utils.log_contains(query)
local logfile = require("core.log"):get_path()
local stdout, ret, stderr = utils.search_file(logfile, query)
if ret == 0 then
return true
end
if not vim.tbl_isempty(stderr) then
error(vim.inspect(stderr))
end
if not vim.tbl_isempty(stdout) then
error(vim.inspect(stdout))
end
if not vim.tbl_isempty(stderr) then
error(vim.inspect(stderr))
end
return false
end
return utils return utils
-- TODO: find a new home for these autocommands -- TODO: find a new home for these autocommands

View file

@ -25,17 +25,4 @@ a.describe("initial start", function()
a.it("should be able to run treesitter without errors", function() a.it("should be able to run treesitter without errors", function()
assert.truthy(vim.treesitter.highlighter.active) assert.truthy(vim.treesitter.highlighter.active)
end) end)
a.it("should be able to load default packages without errors", function()
-- TODO: maybe there's a way to avoid hard-coding the names of the modules?
local startup_plugins = {
"packer",
"lspconfig",
"nlspsettings",
"null-ls",
}
for _, plugin in pairs(startup_plugins) do
assert.truthy(package.loaded[tostring(plugin)])
end
end)
end) end)

98
tests/lsp_spec.lua Normal file
View file

@ -0,0 +1,98 @@
local a = require "plenary.async_lib.tests"
local utils = require "utils"
lvim.lsp.templates_dir = join_paths(get_runtime_dir(), "lvim", "tests", "artifacts")
a.describe("lsp workflow", function()
local Log = require "core.log"
local logfile = Log:get_path()
a.it("shoud be able to delete ftplugin templates", function()
if utils.is_directory(lvim.lsp.templates_dir) then
assert.equal(vim.fn.delete(lvim.lsp.templates_dir, "rf"), 0)
end
assert.False(utils.is_directory(lvim.lsp.templates_dir))
end)
a.it("shoud be able to generate ftplugin templates", function()
if utils.is_directory(lvim.lsp.templates_dir) then
assert.equal(vim.fn.delete(lvim.lsp.templates_dir, "rf"), 0)
end
require("lsp").setup()
-- we need to delay this check until the generation is completed
vim.schedule(function()
assert.True(utils.is_directory(lvim.lsp.templates_dir))
end)
end)
a.it("shoud not attempt to re-generate ftplugin templates", function()
lvim.log.level = "debug"
local plugins = require "plugins"
require("plugin-loader"):load { plugins, lvim.plugins }
if utils.is_file(logfile) then
assert.equal(vim.fn.delete(logfile), 0)
end
assert.True(utils.is_directory(lvim.lsp.templates_dir))
require("lsp").setup()
-- we need to delay this check until the log gets populated
vim.schedule(function()
assert.False(utils.log_contains "templates")
end)
end)
a.it("shoud retrieve supported filetypes correctly", function()
local ocaml = {
name = "ocamlls",
filetypes = { "ocaml", "reason" },
}
local ocaml_fts = require("lsp.utils").get_supported_filetypes(ocaml.name)
assert.True(vim.deep_equal(ocaml.filetypes, ocaml_fts))
local tsserver = {
name = "tsserver",
filetypes = {
"javascript",
"javascriptreact",
"javascript.jsx",
"typescript",
"typescriptreact",
"typescript.tsx",
},
}
local tsserver_fts = require("lsp.utils").get_supported_filetypes(tsserver.name)
assert.True(vim.deep_equal(tsserver.filetypes, tsserver_fts))
end)
a.it("shoud ignore all javascript servers except tsserver and tailwindcss when generating templates", function()
local test_server = { name = "denols", filetypes = {} }
test_server.filetypes = require("lsp.utils").get_supported_filetypes(test_server.name)
assert.True(vim.tbl_contains(test_server.filetypes, "javascript"))
local is_ignored = require("lsp.templates").is_ignored(test_server.name)
assert.True(is_ignored)
local ts_template = utils.join_paths(lvim.lsp.templates_dir, "typescript.lua")
assert.True(utils.file_contains(ts_template, "tsserver"))
assert.True(utils.file_contains(ts_template, "tailwindcss"))
assert.False(utils.file_contains(ts_template, test_server.name))
end)
a.it("shoud not include blacklisted servers in the generated templates", function()
assert.True(utils.is_directory(lvim.lsp.templates_dir))
require("lsp").setup()
local blacklisted = { "jedi_language_server", "pylsp", "sqlls", "sqls", "angularls", "ansiblels" }
for _, file in ipairs(vim.fn.glob(lvim.lsp.templates_dir .. "/*.lua", 1, 1)) do
for _, server in ipairs(blacklisted) do
assert.False(utils.file_contains(file, server))
end
end
end)
end)

9
tests/minimal_init.lua Normal file
View file

@ -0,0 +1,9 @@
local path_sep = vim.loop.os_uname().version:match "Windows" and "\\" or "/"
vim.opt.rtp:append(os.getenv "LUNARVIM_RUNTIME_DIR" .. path_sep .. "lvim")
require("bootstrap"):init()
local config = require "config"
-- config:init()
config:load()

View file

@ -0,0 +1,34 @@
local a = require "plenary.async_lib.tests"
a.describe("plugin-loader", function()
a.it("should be able to load default packages without errors", function()
local plugins = require "plugins"
require("plugin-loader"):load { plugins, lvim.plugins }
-- TODO: maybe there's a way to avoid hard-coding the names of the modules?
local startup_plugins = {
"packer",
}
for _, plugin in ipairs(startup_plugins) do
assert.truthy(package.loaded[plugin])
end
end)
a.it("should be able to load lsp packages without errors", function()
local plugins = require "plugins"
require("plugin-loader"):load { plugins, lvim.plugins }
require("lsp").setup()
local lsp_packages = {
"lspconfig",
"nlspsettings",
"null-ls",
}
for _, plugin in ipairs(lsp_packages) do
assert.truthy(package.loaded[plugin])
end
end)
end)

9
utils/bin/lvim.ps1 Normal file
View file

@ -0,0 +1,9 @@
$env:XDG_DATA_HOME = ($env:XDG_DATA_HOME, "$env:APPDATA", 1 -ne $null)[0]
$env:XDG_CONFIG_HOME = ($env:XDG_CONFIG_HOME, "$LOCALAPPDATA", 1 -ne $null)[0]
$env:XDG_CACHE_HOME = ($env:XDG_CACHE_HOME, "$TEMP", 1 -ne $null)[0]
$env:LUNARVIM_RUNTIME_DIR = ($env:LUNARVIM_RUNTIME_DIR, "$env:XDG_DATA_HOME\lunarvim", 1 -ne $null)[0]
$env:LUNARVIM_CONFIG_DIR = ($env:LUNARVIM_CONFIG_DIR, "$env:XDG_CONFIG_HOME\lvim", 1 -ne $null)[0]
$env:LUNARVIM_CACHE_DIR = ($env:LUNARVIM_CACHE_DIR, "$env:XDG_CACHE_HOME\lvim", 1 -ne $null)[0]
nvim -u "$env:LUNARVIM_RUNTIME_DIR\lvim\init.lua"

View file

@ -10,11 +10,11 @@ rm -f "$LUNARVIM_CONFIG_DIR/plugin/packer_compiled.lua"
lvim() { lvim() {
# TODO: allow running with a minimal_init.lua # TODO: allow running with a minimal_init.lua
nvim -u "$LUNARVIM_RUNTIME_DIR/lvim/init.lua" --cmd "set runtimepath+=$LUNARVIM_RUNTIME_DIR/lvim" "$@" nvim -u "$LUNARVIM_RUNTIME_DIR/lvim/tests/minimal_init.lua" --cmd "set runtimepath+=$LUNARVIM_RUNTIME_DIR/lvim" "$@"
} }
if [ -n "$1" ]; then if [ -n "$1" ]; then
lvim --headless -c "lua require('plenary.busted').run('$1')" lvim --headless -c "lua require('plenary.busted').run('$1')"
else else
lvim --headless -c "PlenaryBustedDirectory tests/ { minimal_init = './init.lua' }" lvim --headless -c "PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal_init.lua' }"
fi fi

View file

@ -55,7 +55,20 @@ lvim.builtin.nvimtree.setup.view.side = "left"
lvim.builtin.nvimtree.show_icons.git = 0 lvim.builtin.nvimtree.show_icons.git = 0
-- if you don't want all the parsers change this to a table of the ones you want -- if you don't want all the parsers change this to a table of the ones you want
lvim.builtin.treesitter.ensure_installed = "maintained" lvim.builtin.treesitter.ensure_installed = {
"bash",
"c",
"javascript",
"json",
"lua",
"python",
"typescript",
"css",
"rust",
"java",
"yaml",
}
lvim.builtin.treesitter.ignore_install = { "haskell" } lvim.builtin.treesitter.ignore_install = { "haskell" }
lvim.builtin.treesitter.highlight.enabled = true lvim.builtin.treesitter.highlight.enabled = true

280
utils/installer/install.ps1 Normal file
View file

@ -0,0 +1,280 @@
$ErrorActionPreference = "Stop" # exit when command fails
# set script variables
# FIXME: temporarily set the branch to the new one
$LV_BRANCH = ($LV_BRANCH, "lang-refactor", 1 -ne $null)[0]
$LV_REMOTE = ($LV_REMOTE, "lunarvim/lunarvim.git", 1 -ne $null)[0]
$INSTALL_PREFIX = ($INSTALL_PREFIX, "$HOME\.local", 1 -ne $null)[0]
$env:XDG_DATA_HOME = ($env:XDG_DATA_HOME, "$env:APPDATA", 1 -ne $null)[0]
$env:XDG_CONFIG_HOME = ($env:XDG_CONFIG_HOME, "$LOCALAPPDATA", 1 -ne $null)[0]
$env:XDG_CACHE_HOME = ($env:XDG_CACHE_HOME, "$TEMP", 1 -ne $null)[0]
$env:LUNARVIM_RUNTIME_DIR = ($env:LUNARVIM_RUNTIME_DIR, "$env:XDG_DATA_HOME\lunarvim", 1 -ne $null)[0]
$env:LUNARVIM_CONFIG_DIR = ($env:LUNARVIM_CONFIG_DIR, "$env:XDG_CONFIG_HOME\lvim", 1 -ne $null)[0]
$env:LUNARVIM_CACHE_DIR = ($env:LUNARVIM_CACHE_DIR, "$env:XDG_CACHE_HOME\lvim", 1 -ne $null)[0]
$__lvim_dirs = (
"$env:LUNARVIM_CONFIG_DIR",
"$env:LUNARVIM_RUNTIME_DIR",
"$env:LUNARVIM_CACHE_DIR"
)
function main($cliargs) {
Write-Output "
88\ 88\
88 | \__|
88 |88\ 88\ 888888$\ 888888\ 888888\ 88\ 88\ 88\ 888888\8888\
88 |88 | 88 |88 __88\ \____88\ 88 __88\\88\ 88 |88 |88 _88 _88\
88 |88 | 88 |88 | 88 | 888888$ |88 | \__|\88\88 / 88 |88 / 88 / 88 |
88 |88 | 88 |88 | 88 |88 __88 |88 | \88$ / 88 |88 | 88 | 88 |
88 |\888888 |88 | 88 |\888888$ |88 | \$ / 88 |88 | 88 | 88 |
\__| \______/ \__| \__| \_______|\__| \_/ \__|\__| \__| \__|
"
__add_separator "80"
# skip this in a Github workflow
if ( $null -eq "$GITHUB_ACTIONS" ) {
install_packer
setup_shim
exit
}
__add_separator "80"
check_system_deps
Write-Output "Would you like to check lunarvim's NodeJS dependencies?"
$answer = Read-Host "[y]es or [n]o (default: no) "
if ("$answer" -eq "y" -or "$answer" -eq "Y") {
install_nodejs_deps
}
Write-Output "Would you like to check lunarvim's Python dependencies?"
$answer = Read-Host "[y]es or [n]o (default: no) "
if ("$answer" -eq "y" -or "$answer" -eq "Y") {
install_python_deps
}
__add_separator "80"
Write-Output "Backing up old LunarVim configuration"
backup_old_config
__add_separator "80"
if ($cliargs.Contains("--overwrite")) {
Write-Output "!!Warning!! -> Removing all lunarvim related config because of the --overwrite flag"
$answer = Read-Host "Would you like to continue? [y]es or [n]o "
if ("$answer" -ne "y" -and "$answer" -ne "Y") {
exit 1
}
foreach ($dir in $__lvim_dirs) {
if (Test-Path "$dir") {
Remove-Item -Force -Recurse "$dir"
}
}
}
if (Test-Path "$env:LUNARVIM_RUNTIME_DIR\site\pack\packer\start\packer.nvim") {
Write-Output "Packer already installed"
}
else {
install_packer
}
__add_separator "80"
if (Test-Path "$env:LUNARVIM_RUNTIME_DIR\lvim\init.lua" ) {
Write-Output "Updating LunarVim"
update_lvim
}
else {
if ($cliargs.Contains("--testing")) {
copy_local_lvim_repository
}
else {
clone_lvim
}
setup_lvim
}
__add_separator "80"
}
function print_missing_dep_msg($dep) {
Write-Output "[ERROR]: Unable to find dependency [$dep]"
Write-Output "Please install it first and re-run the installer. Try: $RECOMMEND_INSTALL $dep"
}
function install_system_package($dep) {
if (Get-Command -Name "winget" -ErrorAction SilentlyContinue) {
Write-Output "[INFO]: Attempting to install dependency [$dep] with winget"
$install_cmd = "winget install --interactive"
}
elseif (Get-Command -Name "scoop" -ErrorAction SilentlyContinue) {
Write-Output "[INFO]: Attempting to install dependency [$dep] with scoop"
# TODO: check if it's fine to not run it with --global
$install_cmd = "scoop install"
}
else {
print_missing_dep_msg "$dep"
exit 1
}
try {
Invoke-Command $install_cmd $dep -ErrorAction Stop
}
catch {
print_missing_dep_msg "$dep"
exit 1
}
}
function check_system_dep($dep) {
try {
Get-Command -Name $dep -ErrorAction Stop | Out-Null
}
catch {
install_system_package "$dep"
}
}
function check_system_deps() {
Write-Output "[INFO]: Checking dependencies.."
check_system_dep "git"
check_system_dep "nvim"
}
function install_nodejs_deps() {
try {
check_system_dep "node"
Invoke-Command npm install -g neovim tree-sitter-cli -ErrorAction Break
}
catch {
print_missing_dep_msg "$dep"
}
}
function install_python_deps() {
try {
check_system_dep "pip"
Invoke-Command python -m pip install --user pynvim -ErrorAction Break
}
catch {
print_missing_dep_msg "$dep"
}
}
function backup_old_config() {
foreach ($dir in $__lvim_dirs) {
# we create an empty folder for subsequent commands \
# that require an existing directory
if ( Test-Path "$dir") {
New-Item "$dir.bak" -ItemType Directory -Force
Copy-Item -Recurse "$dir\*" "$dir.bak\."
}
}
Write-Output "Backup operation complete"
}
function install_packer() {
Invoke-Command -ErrorAction Stop -ScriptBlock { git clone --progress --depth 1 "https://github.com/wbthomason/packer.nvim" "$env:LUNARVIM_RUNTIME_DIR\site\pack\packer\start\packer.nvim" }
}
function copy_local_lvim_repository() {
Write-Output "Copy local LunarVim configuration"
Copy-Item -Path "$((Get-Item $PWD).Parent.Parent.FullName)" -Destination "$env:LUNARVIM_RUNTIME_DIR/lvim" -Recurse
}
function clone_lvim() {
Write-Output "Cloning LunarVim configuration"
try {
Invoke-Command -ErrorAction Stop -ScriptBlock { git clone --progress --branch "$LV_BRANCH" --depth 1 "https://github.com/$LV_REMOTE" "$env:LUNARVIM_RUNTIME_DIR/lvim" }
}
catch {
Write-Output "Failed to clone repository. Installation failed."
exit 1
}
}
function setup_shim() {
if ((Test-Path "$INSTALL_PREFIX\bin") -eq $false) {
New-Item "$INSTALL_PREFIX\bin" -ItemType Directory
}
Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\bin\lvim.ps1" -Destination "$INSTALL_PREFIX\bin\lvim.ps1" -Force
}
function setup_lvim() {
Write-Output "Installing LunarVim shim"
setup_shim
Write-Output "Preparing Packer setup"
if ((Test-Path "$env:LUNARVIM_CONFIG_DIR") -eq $false) {
New-Item "$env:LUNARVIM_CONFIG_DIR" -ItemType Directory
}
Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\installer\config.example-no-ts.lua" `
"$env:LUNARVIM_CONFIG_DIR\config.lua"
Write-Output "Packer setup complete"
__add_separator "80"
Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\installer\config.example.lua" "$env:LUNARVIM_CONFIG_DIR\config.lua"
$answer = Read-Host $(`
"Would you like to create an alias inside your Powershell profile?`n" +`
"(This enables you to start lvim with the command 'lvim') [y]es or [n]o (default: no)" )
if ("$answer" -eq "y" -and "$answer" -eq "Y") {
create_alias
}
__add_separator "80"
Write-Output "Thank you for installing LunarVim!!"
Write-Output "You can start it by running: $INSTALL_PREFIX\bin\lvim.ps1"
Write-Output "Do not forget to use a font with glyphs (icons) support [https://github.com/ryanoasis/nerd-fonts]"
}
function update_lvim() {
try {
Invoke-Command git -C "$env:LUNARVIM_RUNTIME_DIR/lvim" status -uno
}
catch {
git -C "$env:LUNARVIM_RUNTIME_DIR/lvim" pull --ff-only --progress -or
Write-Output "Unable to guarantee data integrity while updating. Please do that manually instead."
exit 1
}
Write-Output "Your LunarVim installation is now up to date!"
}
function __add_separator($div_width) {
"-" * $div_width
Write-Output ""
}
function create_alias {
if($null -eq $(Get-Alias | Select-String "lvim")){
Add-Content -Path $PROFILE -Value $(-join @('Set-Alias lvim "', "$INSTALL_PREFIX", '\bin\lvim.ps1"'))
Write-Output ""
Write-Host 'To use the new alias in this window reload your profile with ". $PROFILE".' -ForegroundColor Yellow
}else {
Write-Output "Alias is already set and will not be reset."
}
}
main "$args"

View file

@ -0,0 +1 @@
Remove-Item -Path "$HOME/.local/share/lunarvim" -Recurse -Force