diff options
author | kylo252 <[email protected]> | 2022-01-03 15:49:07 +0100 |
---|---|---|
committer | kylo252 <[email protected]> | 2022-01-03 15:49:07 +0100 |
commit | e5aa8be8ce54097e4a34220cb2aad114e70f209b (patch) | |
tree | 15e0a3017358b15a0656b6d1f98d2638ae572095 /lua | |
parent | 427ad868d404a254dcbc7d3950946dae0cf205de (diff) | |
parent | 21b41688ee8c5056ffbb2b07df141ce1ccb4b213 (diff) |
Merge branch 'rolling'
Diffstat (limited to 'lua')
27 files changed, 641 insertions, 709 deletions
diff --git a/lua/lvim/bootstrap.lua b/lua/lvim/bootstrap.lua index 702dfae1..2300c753 100644 --- a/lua/lvim/bootstrap.lua +++ b/lua/lvim/bootstrap.lua @@ -1,5 +1,13 @@ local M = {} +if vim.fn.has "nvim-0.6" ~= 1 then + vim.notify("Please upgrade your Neovim base installation. Lunarvim requires v0.6+", vim.log.levels.WARN) + vim.wait(5000, function() + return false + end) + vim.cmd "cquit" +end + local uv = vim.loop local path_sep = uv.os_uname().version:match "Windows" and "\\" or "/" local in_headless = #vim.api.nvim_list_uis() == 0 @@ -11,6 +19,16 @@ function _G.join_paths(...) return result end +---Require a module in protected mode without relying on its cached value +---@param module string +---@return any +function _G.require_clean(module) + package.loaded[module] = nil + _G[module] = nil + local _, requested = pcall(require, module) + return requested +end + ---Get the full path to `$LUNARVIM_RUNTIME_DIR` ---@return string function _G.get_runtime_dir() @@ -96,106 +114,9 @@ end ---Update LunarVim ---pulls the latest changes from github and, resets the startup cache function M:update() - package.loaded["lvim.utils.hooks"] = nil - local _, hooks = pcall(require, "lvim.utils.hooks") - hooks.run_pre_update() - M:update_repo() - hooks.run_post_update() -end - -local function git_cmd(subcmd, opts) - local Job = require "plenary.job" - local Log = require "lvim.core.log" - local args = { "-C", opts.cwd } - vim.list_extend(args, subcmd) - - local stderr = {} - local stdout, ret = Job - :new({ - command = "git", - args = args, - cwd = opts.cwd, - on_stderr = function(_, data) - table.insert(stderr, data) - end, - }) - :sync() - - if not vim.tbl_isempty(stderr) then - Log:debug(stderr) - end - - if not vim.tbl_isempty(stdout) then - Log:debug(stdout) - end - - return ret, stdout -end - ----pulls the latest changes from github -function M:update_repo() - local Log = require "lvim.core.log" - local sub_commands = { - fetch = { "fetch" }, - diff = { "diff", "--quiet", "@{upstream}" }, - merge = { "merge", "--ff-only", "--progress" }, - } - local opts = { - cwd = get_lvim_base_dir(), - } - Log:info "Checking for updates" - - local ret = git_cmd(sub_commands.fetch, opts) - if ret ~= 0 then - Log:error "Update failed! Check the log for further information" - return - end - - ret = git_cmd(sub_commands.diff, opts) - - if ret == 0 then - Log:info "LunarVim is already up-to-date" - return - end - - ret = git_cmd(sub_commands.merge, opts) - - if ret ~= 0 then - Log:error "Update failed! Please pull the changes manually instead." - return - end -end - ----Get currently installed version of LunarVim ----@param type string can be "short" ----@return string -function M:get_version(type) - type = type or "" - local opts = { cwd = get_lvim_base_dir() } - - local _, branch = git_cmd({ "branch", "--show-current" }, opts) - - local is_on_master = branch == "master" - if not is_on_master then - local log_status_ok, log_results = git_cmd({ "log", "--pretty=format:%h", "-1" }, opts) - local abbrev_version = log_results[1] or "" - if not log_status_ok or string.match(abbrev_version, "%d") == nil then - return nil - end - return "dev-" .. abbrev_version - end - - local tag_status_ok, results = git_cmd({ "describe", "--tags" }, opts) - local lvim_full_ver = results[1] or "" - - if not tag_status_ok or string.match(lvim_full_ver, "%d") == nil then - return nil - end - if type == "short" then - return vim.fn.split(lvim_full_ver, "-")[1] - else - return string.sub(lvim_full_ver, 1, #lvim_full_ver - 1) - end + require_clean("lvim.utils.hooks").run_pre_update() + require_clean("lvim.utils.git").update_base_lvim() + require_clean("lvim.utils.hooks").run_post_update() end return M diff --git a/lua/lvim/config/init.lua b/lua/lvim/config/init.lua index 9b6d36f0..145173b1 100644 --- a/lua/lvim/config/init.lua +++ b/lua/lvim/config/init.lua @@ -66,6 +66,11 @@ local function handle_deprecated_settings() deprecation_notice(string.format("lvim.lang.%s", lang)) end end + + -- lvim.lsp.popup_border + if vim.tbl_contains(vim.tbl_keys(lvim.lsp), "popup_border") then + deprecation_notice "lvim.lsp.popup_border" + end end --- Override the configuration with a user provided one @@ -97,9 +102,7 @@ end --- Override the configuration with a user provided one -- @param config_path The path to the configuration overrides function M:reload() - package.loaded["lvim.utils.hooks"] = nil - local _, hooks = pcall(require, "lvim.utils.hooks") - hooks.run_pre_reload() + require_clean("lvim.utils.hooks").run_pre_reload() M:init() M:load() @@ -110,7 +113,7 @@ function M:reload() local plugin_loader = require "lvim.plugin-loader" plugin_loader.load { plugins, lvim.plugins } - hooks.run_post_reload() + require_clean("lvim.utils.hooks").run_post_reload() end return M diff --git a/lua/lvim/core/autocmds.lua b/lua/lvim/core/autocmds.lua index e4577e63..712fd323 100644 --- a/lua/lvim/core/autocmds.lua +++ b/lua/lvim/core/autocmds.lua @@ -78,7 +78,7 @@ local get_format_on_save_opts = function() end function M.enable_format_on_save(opts) - local fmd_cmd = string.format(":silent lua vim.lsp.buf.formatting_sync({}, %s)", opts.timeout_ms) + local fmd_cmd = string.format(":silent lua vim.lsp.buf.formatting_sync({}, %s)", opts.timeout) M.define_augroups { format_on_save = { { "BufWritePre", opts.pattern, fmd_cmd } }, } @@ -86,16 +86,12 @@ function M.enable_format_on_save(opts) end function M.disable_format_on_save() - M.remove_augroup "format_on_save" + M.disable_augroup "format_on_save" Log:debug "disabled format-on-save" end function M.configure_format_on_save() if lvim.format_on_save then - if vim.fn.exists "#format_on_save#BufWritePre" == 1 then - M.remove_augroup "format_on_save" - Log:debug "reloading format-on-save configuration" - end local opts = get_format_on_save_opts() M.enable_format_on_save(opts) else @@ -112,24 +108,73 @@ function M.toggle_format_on_save() end end -function M.remove_augroup(name) - if vim.fn.exists("#" .. name) == 1 then - vim.cmd("au! " .. name) - end +function M.enable_lsp_document_highlight(client_id) + M.define_augroups({ + lsp_document_highlight = { + { + "CursorHold", + "<buffer>", + string.format("lua require('lvim.lsp.utils').conditional_document_highlight(%d)", client_id), + }, + { + "CursorMoved", + "<buffer>", + "lua vim.lsp.buf.clear_references()", + }, + }, + }, true) +end + +function M.disable_lsp_document_highlight() + M.disable_augroup "lsp_document_highlight" +end + +function M.enable_code_lens_refresh() + M.define_augroups({ + lsp_code_lens_refresh = { + { + "InsertLeave ", + "<buffer>", + "lua vim.lsp.codelens.refresh()", + }, + { + "InsertLeave ", + "<buffer>", + "lua vim.lsp.codelens.display()", + }, + }, + }, true) end -function M.define_augroups(definitions) -- {{{1 - -- Create autocommand groups based on the passed definitions - -- - -- The key will be the name of the group, and each definition - -- within the group should have: - -- 1. Trigger - -- 2. Pattern - -- 3. Text - -- just like how they would normally be defined from Vim itself +function M.disable_code_lens_refresh() + M.disable_augroup "lsp_code_lens_refresh" +end + +--- Disable autocommand groups if it exists +--- This is more reliable than trying to delete the augroup itself +---@param name string the augroup name +function M.disable_augroup(name) + -- defer the function in case the autocommand is still in-use + vim.schedule(function() + if vim.fn.exists("#" .. name) == 1 then + vim.cmd("augroup " .. name) + vim.cmd "autocmd!" + vim.cmd "augroup END" + end + end) +end + +--- Create autocommand groups based on the passed definitions +---@param definitions table contains trigger, pattern and text. The key will be used as a group name +---@param buffer boolean indicate if the augroup should be local to the buffer +function M.define_augroups(definitions, buffer) for group_name, definition in pairs(definitions) do vim.cmd("augroup " .. group_name) - vim.cmd "autocmd!" + if buffer then + vim.cmd [[autocmd! * <buffer>]] + else + vim.cmd [[autocmd!]] + end for _, def in pairs(definition) do local command = table.concat(vim.tbl_flatten { "autocmd", def }, " ") diff --git a/lua/lvim/core/dashboard.lua b/lua/lvim/core/dashboard.lua index 0f62d973..438b46f3 100644 --- a/lua/lvim/core/dashboard.lua +++ b/lua/lvim/core/dashboard.lua @@ -73,7 +73,7 @@ M.setup = function() vim.g.dashboard_session_directory = lvim.builtin.dashboard.session_directory local lvim_site = "lunarvim.org" - local lvim_version = require("lvim.bootstrap"):get_version "short" + local lvim_version = require("lvim.utils.git"):get_lvim_version "short" local num_plugins_loaded = #vim.fn.globpath(get_runtime_dir() .. "/site/pack/packer/start", "*", 0, 1) local footer = { diff --git a/lua/lvim/core/info.lua b/lua/lvim/core/info.lua index df7b7061..7577f296 100644 --- a/lua/lvim/core/info.lua +++ b/lua/lvim/core/info.lua @@ -19,9 +19,8 @@ end local function make_formatters_info(ft) local null_formatters = require "lvim.lsp.null-ls.formatters" - local registered_formatters = null_formatters.list_registered_providers(ft) - -- print("reg", vim.inspect(registered_formatters)) - local supported_formatters = null_formatters.list_available(ft) + local registered_formatters = null_formatters.list_registered(ft) + local supported_formatters = null_formatters.list_supported(ft) local section = { "Formatters info", fmt( @@ -37,8 +36,7 @@ end local function make_code_actions_info(ft) local null_actions = require "lvim.lsp.null-ls.code_actions" - local registered_actions = null_actions.list_registered_providers(ft) - local supported_actions = null_actions.list_available(ft) + local registered_actions = null_actions.list_registered(ft) local section = { "Code actions info", fmt( @@ -46,7 +44,6 @@ local function make_code_actions_info(ft) table.concat(registered_actions, " , "), vim.tbl_count(registered_actions) > 0 and " " or "" ), - fmt("* Supported: %s", str_list(supported_actions)), } return section @@ -54,8 +51,8 @@ end local function make_linters_info(ft) local null_linters = require "lvim.lsp.null-ls.linters" - local supported_linters = null_linters.list_available(ft) - local registered_linters = null_linters.list_registered_providers(ft) + local supported_linters = null_linters.list_supported(ft) + local registered_linters = null_linters.list_registered(ft) local section = { "Linters info", fmt( @@ -168,21 +165,20 @@ function M.toggle_popup(ft) local function set_syntax_hl() vim.cmd [[highlight LvimInfoIdentifier gui=bold]] vim.cmd [[highlight link LvimInfoHeader Type]] - vim.cmd [[let m=matchadd("LvimInfoHeader", "Treesitter info")]] - vim.cmd [[let m=matchadd("LvimInfoHeader", "Language Server Protocol (LSP) info")]] - vim.cmd [[let m=matchadd("LvimInfoHeader", "Formatters info")]] - vim.cmd [[let m=matchadd("LvimInfoHeader", "Linters info")]] - vim.cmd [[let m=matchadd("LvimInfoHeader", "Code actions info")]] - vim.cmd('let m=matchadd("LvimInfoIdentifier", " ' .. ft .. '$")') - vim.cmd 'let m=matchadd("string", "true")' - vim.cmd 'let m=matchadd("string", "active")' - vim.cmd 'let m=matchadd("boolean", "inactive")' - vim.cmd 'let m=matchadd("string", "")' - vim.cmd 'let m=matchadd("error", "false")' - -- tbl_set_highlight(registered_providers, "LvimInfoIdentifier") - tbl_set_highlight(require("lvim.lsp.null-ls.formatters").list_available(ft), "LvimInfoIdentifier") - tbl_set_highlight(require("lvim.lsp.null-ls.linters").list_available(ft), "LvimInfoIdentifier") - tbl_set_highlight(require("lvim.lsp.null-ls.code_actions").list_available(ft), "LvimInfoIdentifier") + vim.fn.matchadd("LvimInfoHeader", "Treesitter info") + vim.fn.matchadd("LvimInfoHeader", "Language Server Protocol (LSP) info") + vim.fn.matchadd("LvimInfoHeader", "Formatters info") + vim.fn.matchadd("LvimInfoHeader", "Linters info") + vim.fn.matchadd("LvimInfoHeader", "Code actions info") + vim.fn.matchadd("LvimInfoIdentifier", " " .. ft .. "$") + vim.fn.matchadd("string", "true") + vim.fn.matchadd("string", "active") + vim.fn.matchadd("string", "") + vim.fn.matchadd("boolean", "inactive") + vim.fn.matchadd("error", "false") + tbl_set_highlight(require("lvim.lsp.null-ls.formatters").list_registered(ft), "LvimInfoIdentifier") + tbl_set_highlight(require("lvim.lsp.null-ls.linters").list_registered(ft), "LvimInfoIdentifier") + tbl_set_highlight(require("lvim.lsp.null-ls.code_actions").list_registered(ft), "LvimInfoIdentifier") end local Popup = require("lvim.interface.popup"):new { diff --git a/lua/lvim/core/log.lua b/lua/lvim/core/log.lua index f51b8af6..be7930ba 100644 --- a/lua/lvim/core/log.lua +++ b/lua/lvim/core/log.lua @@ -9,29 +9,16 @@ Log.levels = { WARN = 4, ERROR = 5, } - vim.tbl_add_reverse_lookup(Log.levels) +local notify_opts = {} + function Log:init() local status_ok, structlog = pcall(require, "structlog") if not status_ok then return nil end - local notify_handler = require "lvim.core.notify" - - ---Check if notify is available - ---@return boolean - local is_notify_available = function() - local in_headless = #vim.api.nvim_list_uis() == 0 - --We can't rely on lvim.builtin.notify.active since this can be used before the config loader - local has_notify_plugin = pcall(require, "notify") - if not in_headless and has_notify_plugin then - return true - end - return false - end - local log_level = Log.levels[(lvim.log.level):upper() or "WARN"] local lvim_log = { lvim = { @@ -64,50 +51,94 @@ function Log:init() }, } - if is_notify_available() then - table.insert( - lvim_log.lvim.sinks, - structlog.sinks.NvimNotify(Log.levels.INFO, { - processors = { - notify_handler.default_namer, - notify_handler.params_injecter, - }, - formatter = structlog.formatters.Format( -- - "%s", - { "msg" }, - { blacklist_all = true } - ), - params_map = { - icon = "icon", - keep = "keep", - on_open = "on_open", - on_close = "on_close", - timeout = "timeout", - title = "title", - }, - }) - ) - end - structlog.configure(lvim_log) - local logger = structlog.get_logger "lvim" + -- Overwrite `vim.notify` to use the logger if lvim.log.override_notify then - logger:log(Log.levels.INFO, "Ignoring request to override vim.notify with structlog due to instabilities") + vim.notify = function(msg, vim_log_level, opts) + notify_opts = opts or {} + + -- vim_log_level can be omitted + if vim_log_level == nil then + vim_log_level = Log.levels["INFO"] + elseif type(vim_log_level) == "string" then + vim_log_level = Log.levels[(vim_log_level):upper()] or Log.levels["INFO"] + else + -- https://github.com/neovim/neovim/blob/685cf398130c61c158401b992a1893c2405cd7d2/runtime/lua/vim/lsp/log.lua#L5 + vim_log_level = vim_log_level + 1 + end + + logger:log(vim_log_level, msg) + end end return logger end +--- Configure the sink in charge of logging notifications +---@param notif_handle table The implementation used by the sink for displaying the notifications +function Log:configure_notifications(notif_handle) + local status_ok, structlog = pcall(require, "structlog") + if not status_ok then + return + end + + local default_namer = function(logger, entry) + entry["title"] = logger.name + return entry + end + + local notify_opts_injecter = function(_, entry) + for key, value in pairs(notify_opts) do + entry[key] = value + end + notify_opts = {} + return entry + end + + local sink = structlog.sinks.NvimNotify(Log.levels.INFO, { + processors = { + default_namer, + notify_opts_injecter, + }, + formatter = structlog.formatters.Format( -- + "%s", + { "msg" }, + { blacklist_all = true } + ), + -- This should probably not be hard-coded + params_map = { + icon = "icon", + keep = "keep", + on_open = "on_open", + on_close = "on_close", + timeout = "timeout", + title = "title", + }, + impl = notif_handle, + }) + + table.insert(self.__handle.sinks, sink) +end + --- Adds a log entry using Plenary.log ----@fparam msg any +---@param msg any ---@param level string [same as vim.log.log_levels] function Log:add_entry(level, msg, event) - if self.__handle then - self.__handle:log(level, vim.inspect(msg), event) + local logger = self:get_logger() + if not logger then return end + logger:log(level, vim.inspect(msg), event) +end + +---Retrieves the handle of the logger object +---@return table|nil logger handle if found +function Log:get_logger() + if self.__handle then + return self.__handle + end local logger = self:init() if not logger then @@ -115,7 +146,7 @@ function Log:add_entry(level, msg, event) end self.__handle = logger - self.__handle:log(level, vim.inspect(msg), event) + return logger end ---Retrieves the path of the logfile diff --git a/lua/lvim/core/lualine/components.lua b/lua/lvim/core/lualine/components.lua index 9cf67616..b1387afa 100644 --- a/lua/lvim/core/lualine/components.lua +++ b/lua/lvim/core/lualine/components.lua @@ -104,17 +104,16 @@ return { -- add formatter local formatters = require "lvim.lsp.null-ls.formatters" - local supported_formatters = formatters.list_registered_providers(buf_ft) + local supported_formatters = formatters.list_registered(buf_ft) vim.list_extend(buf_client_names, supported_formatters) -- add linter local linters = require "lvim.lsp.null-ls.linters" - local supported_linters = linters.list_registered_providers(buf_ft) + local supported_linters = linters.list_registered(buf_ft) vim.list_extend(buf_client_names, supported_linters) return "[" .. table.concat(buf_client_names, ", ") .. "]" end, - -- icon = " ", color = { gui = "bold" }, cond = conditions.hide_in_width, }, diff --git a/lua/lvim/core/notify.lua b/lua/lvim/core/notify.lua index 5339357b..cb62778f 100644 --- a/lua/lvim/core/notify.lua +++ b/lua/lvim/core/notify.lua @@ -1,45 +1,59 @@ local M = {} -function M.config() - local pallete = require "onedarker.palette" - - lvim.builtin.notify = { - active = false, - on_config_done = nil, - -- TODO: update after https://github.com/rcarriga/nvim-notify/pull/24 - opts = { - ---@usage Animation style one of { "fade", "slide", "fade_in_slide_out", "static" } - stages = "slide", - - ---@usage timeout for notifications in ms, default 5000 - timeout = 5000, - - ---@usage highlight behind the window for stages that change opacity - background_colour = pallete.fg, - - ---@usage Icons for the different levels - icons = { - ERROR = "", - WARN = "", - INFO = "", - DEBUG = "", - TRACE = "✎", - }, +local Log = require "lvim.core.log" + +local defaults = { + active = false, + on_config_done = nil, + opts = { + ---@usage Animation style one of { "fade", "slide", "fade_in_slide_out", "static" } + stages = "slide", + + ---@usage Function called when a new window is opened, use for changing win settings/config + on_open = nil, + + ---@usage Function called when a window is closed + on_close = nil, + + ---@usage timeout for notifications in ms, default 5000 + timeout = 5000, + + -- Render function for notifications. See notify-render() + render = "default", + + ---@usage highlight behind the window for stages that change opacity + background_colour = "Normal", + + ---@usage minimum width for notification windows + minimum_width = 50, + + ---@usage Icons for the different levels + icons = { + ERROR = "", + WARN = "", + INFO = "", + DEBUG = "", + TRACE = "✎", }, - } + }, +} + +function M.config() + lvim.builtin.notify = vim.tbl_deep_extend("force", defaults, lvim.builtin.notify or {}) end -M.params_injecter = function(_, entry) - -- FIXME: this is currently getting ignored or is not passed correctly - for key, value in pairs(lvim.builtin.notify.opts) do - entry[key] = value +function M.setup() + if #vim.api.nvim_list_uis() == 0 then + -- no need to configure notifications in headless + return end - return entry -end -M.default_namer = function(logger, entry) - entry["title"] = logger.name - return entry + local opts = lvim.builtin.notify and lvim.builtin.notify.opts or defaults + local notify = require "notify" + + notify.setup(opts) + vim.notify = notify + Log:configure_notifications(notify) end return M diff --git a/lua/lvim/core/telescope/custom-finders.lua b/lua/lvim/core/telescope/custom-finders.lua index 5ce1485c..18307fbd 100644 --- a/lua/lvim/core/telescope/custom-finders.lua +++ b/lua/lvim/core/telescope/custom-finders.lua @@ -82,4 +82,14 @@ function M.view_lunarvim_changelog() }):find() end +-- Smartly opens either git_files or find_files, depending on whether the working directory is +-- contained in a Git repo. +function M.find_project_files() + local ok = pcall(builtin.git_files) + + if not ok then + builtin.find_files() + end +end + return M diff --git a/lua/lvim/core/treesitter.lua b/lua/lvim/core/treesitter.lua index 8dbbcacb..d8b0c136 100644 --- a/lua/lvim/core/treesitter.lua +++ b/lua/lvim/core/treesitter.lua @@ -74,16 +74,20 @@ M.config = function() end M.setup = function() + -- avoid running in headless mode since it's harder to detect failures + if #vim.api.nvim_list_uis() == 0 then + Log:debug "headless mode detected, skipping running setup for treesitter" + return + end + local status_ok, treesitter_configs = pcall(require, "nvim-treesitter.configs") if not status_ok then - Log:get_default().error "Failed to load nvim-treesitter.configs" + Log:error "Failed to load nvim-treesitter.configs" return end local opts = vim.deepcopy(lvim.builtin.treesitter) - -- avoid running any installers in headless mode since it's harder to detect failures - opts.ensure_installed = #vim.api.nvim_list_uis() == 0 and {} or opts.ensure_installed treesitter_configs.setup(opts) if lvim.builtin.treesitter.on_config_done then diff --git a/lua/lvim/core/which-key.lua b/lua/lvim/core/which-key.lua index 88af028f..8691a9a6 100644 --- a/lua/lvim/core/which-key.lua +++ b/lua/lvim/core/which-key.lua @@ -61,14 +61,14 @@ M.config = function() -- NOTE: Prefer using : over <cmd> as the latter avoids going back in normal-mode. -- see https://neovim.io/doc/user/map.html#:map-cmd vmappings = { - ["/"] = { "<ESC><CMD>lua require('Comment.api').gc(vim.fn.visualmode())<CR>", "Comment" }, + ["/"] = { "<ESC><CMD>lua require('Comment.api').toggle_linewise_op(vim.fn.visualmode())<CR>", "Comment" }, }, mappings = { ["w"] = { "<cmd>w!<CR>", "Save" }, ["q"] = { "<cmd>q!<CR>", "Quit" }, - ["/"] = { "<cmd>lua require('Comment').toggle()<CR>", "Comment" }, + ["/"] = { "<cmd>lua require('Comment.api').toggle_current_linewise()<CR>", "Comment" }, ["c"] = { "<cmd>BufferClose!<CR>", "Close Buffer" }, - ["f"] = { "<cmd>Telescope find_files<CR>", "Find File" }, + ["f"] = { require("lvim.core.telescope.custom-finders").find_project_files, "Find File" }, ["h"] = { "<cmd>nohlsearch<CR>", "No Highlight" }, b = { name = "Buffers", @@ -140,23 +140,17 @@ M.config = function() l = { name = "LSP", a = { "<cmd>lua require('lvim.core.telescope').code_actions()<cr>", "Code Action" }, - d = { - "<cmd>Telescope lsp_document_diagnostics<cr>", - "Document Diagnostics", - }, - w = { - "<cmd>Telescope lsp_workspace_diagnostics<cr>", - "Workspace Diagnostics", - }, + d = { "<cmd>Telescope diagnostics bufnr=0 theme=get_ivy<cr>", "Buffer Diagnostics" }, + w = { "<cmd>Telescope diagnostics<cr>", "Diagnostics" }, f = { "<cmd>lua vim.lsp.buf.formatting()<cr>", "Format" }, i = { "<cmd>LspInfo<cr>", "Info" }, I = { "<cmd>LspInstallInfo<cr>", "Installer Info" }, j = { - "<cmd>lua vim.lsp.diagnostic.goto_next({popup_opts = {border = lvim.lsp.popup_border}})<cr>", + "<cmd>lua vim.diagnostic.goto_next()<cr>", "Next Diagnostic", }, k = { - "<cmd>lua vim.lsp.diagnostic.goto_prev({popup_opts = {border = lvim.lsp.popup_border}})<cr>", + "<cmd>lua vim.diagnostic.goto_prev()<cr>", "Prev Diagnostic", }, l = { "<cmd>lua vim.lsp.codelens.run()<cr>", "CodeLens Action" }, @@ -166,7 +160,7 @@ M.config = function() t = { "<cmd>lua require('lvim.lsp.peek').Peek('typeDefinition')<cr>", "Type Definition" }, i = { "<cmd>lua require('lvim.lsp.peek').Peek('implementation')<cr>", "Implementation" }, }, - q = { "<cmd>lua vim.lsp.diagnostic.set_loclist()<cr>", "Quickfix" }, + q = { "<cmd>lua vim.diagnostic.setloclist()<cr>", "Quickfix" }, r = { "<cmd>lua vim.lsp.buf.rename()<cr>", "Rename" }, s = { "<cmd>Telescope lsp_document_symbols<cr>", "Document Symbols" }, S = { diff --git a/lua/lvim/lsp/config.lua b/lua/lvim/lsp/config.lua index 5cfe5b1f..8c7a0dd9 100644 --- a/lua/lvim/lsp/config.lua +++ b/lua/lvim/lsp/config.lua @@ -32,7 +32,11 @@ return { }, document_highlight = true, code_lens_refresh = true, - popup_border = "single", + float = { + focusable = false, + style = "minimal", + border = "rounded", + }, on_attach_callback = nil, on_init_callback = nil, automatic_servers_installation = true, @@ -61,13 +65,14 @@ return { "angularls", "ansiblels", "ccls", - "cssmodules_ls", "csharp_ls", + "cssmodules_ls", "denols", "ember", "emmet_ls", "eslint", "eslintls", + "grammarly", "graphql", "jedi_language_server", "ltex", @@ -75,15 +80,17 @@ return { "pylsp", "quick_lint_js", "rome", - "sorbet", - "sqlls", - "sqls", "solang", + "solidity_ls", + "sorbet", "sourcekit", "spectral", + "sqlls", + "sqls", "stylelint_lsp", "tailwindcss", "tflint", "volar", + "zk", }, } diff --git a/lua/lvim/lsp/handlers.lua b/lua/lvim/lsp/handlers.lua index 45f73e91..5da0b21e 100644 --- a/lua/lvim/lsp/handlers.lua +++ b/lua/lvim/lsp/handlers.lua @@ -11,130 +11,15 @@ function M.setup() severity_sort = lvim.lsp.diagnostics.severity_sort, float = lvim.lsp.diagnostics.float, } - if vim.fn.has "nvim-0.6" == 1 then - vim.diagnostic.config(config) - else - vim.lsp.handlers["textDocument/publishDiagnostics"] = function(_, _, params, client_id, _) - local uri = params.uri - local bufnr = vim.uri_to_bufnr(uri) - if not bufnr then - return - end - - local diagnostics = params.diagnostics - vim.lsp.diagnostic.save(diagnostics, bufnr, client_id) - if not vim.api.nvim_buf_is_loaded(bufnr) then - return - end - vim.lsp.diagnostic.display(diagnostics, bufnr, client_id, config) - end - - vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { - border = lvim.lsp.popup_border, - }) - - vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { - border = lvim.lsp.popup_border, - }) - end + vim.diagnostic.config(config) + vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, lvim.lsp.float) + vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, lvim.lsp.float) end function M.show_line_diagnostics() - if vim.fn.has "nvim-0.6" == 1 then - return vim.diagnostic.open_float(0, { scope = "line" }) - end - - local function split_by_chunk(text, chunkSize) - local s = {} - for i = 1, #text, chunkSize do - s[#s + 1] = text:sub(i, i + chunkSize - 1) - end - return s - end - local diagnostics = vim.lsp.diagnostic.get_line_diagnostics() - local severity_highlight = { - "LspDiagnosticsFloatingError", - "LspDiagnosticsFloatingWarning", - "LspDiagnosticsFloatingInformation", - "LspDiagnosticsFloatingHint", - } - local ok, vim_diag = pcall(require, "vim.diagnostic") - if ok then - local buf_id = vim.api.nvim_win_get_buf(0) - local win_id = vim.api.nvim_get_current_win() - local cursor_position = vim.api.nvim_win_get_cursor(win_id) - severity_highlight = { - "DiagnosticFloatingError", - "DiagnosticFloatingWarn", - "DiagnosticFloatingInfo", - "DiagnosticFloatingHint", - } - diagnostics = vim_diag.get(buf_id, { lnum = cursor_position[1] - 1 }) - end - local lines = {} - local max_width = vim.fn.winwidth(0) - 5 - local height = #diagnostics - local width = 0 - local opts = {} - local close_events = { "CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre" } - if height == 0 then - return - end - local bufnr = vim.api.nvim_create_buf(false, true) - local diag_message - table.sort(diagnostics, function(a, b) - return a.severity < b.severity - end) - - local hash = {} - local diagnostics_no_dupes = {} - for _, v in ipairs(diagnostics) do - if not hash[v["message"]] then - diagnostics_no_dupes[#diagnostics_no_dupes + 1] = v -- you could print here instead of saving to result table if you wanted - hash[v["message"]] = true - end - end - -- print(vim.inspect(diagnostics_no_dupes)) - - for i, diagnostic in ipairs(diagnostics_no_dupes) do - local source = diagnostic.source - diag_message = diagnostic.message:gsub("[\n\r]", " ") - if source then - if string.find(source, "/") then - source = string.sub(diagnostic.source, string.find(diagnostic.source, "([%w-_]+)$")) - end - diag_message = string.format("%d. %s: %s", i, source, diag_message) - else - diag_message = string.format("%d. %s", i, diag_message) - end - if diagnostic.code then - diag_message = string.format("%s [%s]", diag_message, diagnostic.code) - end - local msgs = split_by_chunk(diag_message, max_width) - for _, diag in ipairs(msgs) do - table.insert(lines, { message = diag, severity = diagnostic.severity }) - width = math.max(diag:len(), width) - end - end - height = #lines - opts = vim.lsp.util.make_floating_popup_options(width, height, opts) - opts["style"] = "minimal" - opts["border"] = "rounded" - opts["focusable"] = true - - vim.api.nvim_buf_set_option(bufnr, "bufhidden", "wipe") - local winnr = vim.api.nvim_open_win(bufnr, false, opts) - vim.api.nvim_win_set_option(winnr, "winblend", 0) - vim.api.nvim_buf_set_var(bufnr, "lsp_floating_window", winnr) - for i, diag in ipairs(lines) do - vim.api.nvim_buf_set_lines(bufnr, i - 1, i - 1, 0, { diag.message }) - vim.api.nvim_buf_add_highlight(bufnr, -1, severity_highlight[diag.severity], i - 1, 0, diag.message:len()) - end - - vim.api.nvim_command( - "autocmd QuitPre <buffer> ++nested ++once lua pcall(vim.api.nvim_win_close, " .. winnr .. ", true)" - ) - vim.lsp.util.close_preview_autocmd(close_events, winnr) + local config = lvim.lsp.diagnostics.float + config.scope = "line" + return vim.diagnostic.open_float(0, config) end return M diff --git a/lua/lvim/lsp/init.lua b/lua/lvim/lsp/init.lua index 68a64d6c..0be13484 100644 --- a/lua/lvim/lsp/init.lua +++ b/lua/lvim/lsp/init.lua @@ -1,24 +1,13 @@ local M = {} local Log = require "lvim.core.log" local utils = require "lvim.utils" +local autocmds = require "lvim.core.autocmds" local function lsp_highlight_document(client) if lvim.lsp.document_highlight == false then return -- we don't need further end - -- Set autocommands conditional on server_capabilities - if client.resolved_capabilities.document_highlight then - vim.api.nvim_exec( - [[ - augroup lsp_document_highlight - autocmd! * <buffer> - autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight() - autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() - augroup END - ]], - false - ) - end + autocmds.enable_lsp_document_highlight(client.id) end local function lsp_code_lens_refresh(client) @@ -27,16 +16,7 @@ local function lsp_code_lens_refresh(client) end if client.resolved_capabilities.code_lens then - vim.api.nvim_exec( - [[ - augroup lsp_code_lens_refresh - autocmd! * <buffer> - autocmd InsertLeave <buffer> lua vim.lsp.codelens.refresh() - autocmd InsertLeave <buffer> lua vim.lsp.codelens.display() - augroup END - ]], - false - ) + autocmds.enable_code_lens_refresh() end end @@ -101,6 +81,15 @@ local function select_default_formater(client) end end +function M.common_on_exit(_, _) + if lvim.lsp.document_highlight then + autocmds.disable_lsp_document_highlight() + end + if lvim.lsp.code_lens_refresh then + autocmds.disable_code_lens_refresh() + end +end + function M.common_on_init(client, bufnr) if lvim.lsp.on_init_callback then lvim.lsp.on_init_callback(client, bufnr) @@ -132,17 +121,11 @@ function M.get_common_opts() return { on_attach = M.common_on_attach, on_init = M.common_on_init, + on_exit = M.common_on_exit, capabilities = M.common_capabilities(), } end -local LSP_DEPRECATED_SIGN_MAP = { - ["DiagnosticSignError"] = "LspDiagnosticsSignError", - ["DiagnosticSignWarn"] = "LspDiagnosticsSignWarning", - ["DiagnosticSignHint"] = "LspDiagnosticsSignHint", - ["DiagnosticSignInfo"] = "LspDiagnosticsSignInformation", -} - function M.setup() Log:debug "Setting up LSP support" @@ -151,13 +134,7 @@ function M.setup() return end - local is_neovim_5 = vim.fn.has "nvim-0.6" ~= 1 - for _, sign in ipairs(lvim.lsp.diagnostics.signs.values) do - local lsp_sign_name = LSP_DEPRECATED_SIGN_MAP[sign.name] - if is_neovim_5 and lsp_sign_name then - vim.fn.sign_define(lsp_sign_name, { texthl = lsp_sign_name, text = sign.text, numhl = lsp_sign_name }) - end vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = sign.name }) end @@ -171,7 +148,7 @@ function M.setup() require("lvim.lsp.null-ls").setup() - require("lvim.core.autocmds").configure_format_on_save() + autocmds.configure_format_on_save() end return M diff --git a/lua/lvim/lsp/manager.lua b/lua/lvim/lsp/manager.lua index c95b9f69..6c748020 100644 --- a/lua/lvim/lsp/manager.lua +++ b/lua/lvim/lsp/manager.lua @@ -24,6 +24,7 @@ local function resolve_config(name, user_config) local config = { on_attach = require("lvim.lsp").common_on_attach, on_init = require("lvim.lsp").common_on_init, + on_exit = require("lvim.lsp").common_on_exit, capabilities = require("lvim.lsp").common_capabilities(), } diff --git a/lua/lvim/lsp/null-ls/code_actions.lua b/lua/lvim/lsp/null-ls/code_actions.lua index ff59fabf..bf6492b5 100644 --- a/lua/lvim/lsp/null-ls/code_actions.lua +++ b/lua/lvim/lsp/null-ls/code_actions.lua @@ -14,20 +14,11 @@ local is_registered = function(name) return require("null-ls.sources").is_registered(query) end -function M.list_registered_providers(filetype) +function M.list_registered(filetype) local registered_providers = services.list_registered_providers_names(filetype) return registered_providers[METHOD] or {} end -function M.list_available(filetype) - local availables = require("null-ls.sources").get_available(filetype, METHOD) - local actors = vim.tbl_map(function(src) - return src.name - end, availables) - table.sort(actors) - return actors -end - function M.list_configured(actions_configs) local actors, errors = {}, {} diff --git a/lua/lvim/lsp/null-ls/formatters.lua b/lua/lvim/lsp/null-ls/formatters.lua index b2e191c5..0613f16f 100644 --- a/lua/lvim/lsp/null-ls/formatters.lua +++ b/lua/lvim/lsp/null-ls/formatters.lua @@ -12,26 +12,18 @@ local is_registered = function(name) return require("null-ls.sources").is_registered(query) end -function M.list_registered_providers(filetype) +function M.list_registered(filetype) local null_ls_methods = require "null-ls.methods" local formatter_method = null_ls_methods.internal["FORMATTING"] local registered_providers = services.list_registered_providers_names(filetype) return registered_providers[formatter_method] or {} end -function M.list_available(filetype) - local formatters = {} - local tbl = require "lvim.utils.table" - for _, provider in pairs(null_ls.builtins.formatting) do - if tbl.contains(provider.filetypes or {}, function(ft) - return ft == "*" or ft == filetype - end) then - table.insert(formatters, provider.name) - end - end - - table.sort(formatters) - return formatters +function M.list_supported(filetype) + local s = require "null-ls.sources" + local supported_formatters = s.get_supported(filetype, "formatting") + table.sort(supported_formatters) + return supported_formatters end function M.list_configured(formatter_configs) diff --git a/lua/lvim/lsp/null-ls/init.lua b/lua/lvim/lsp/null-ls/init.lua index f5e820e8..68e20c98 100644 --- a/lua/lvim/lsp/null-ls/init.lua +++ b/lua/lvim/lsp/null-ls/init.lua @@ -9,14 +9,8 @@ function M:setup() return end - null_ls.config(lvim.lsp.null_ls.config) local default_opts = require("lvim.lsp").get_common_opts() - - if vim.tbl_isempty(lvim.lsp.null_ls.setup or {}) then - lvim.lsp.null_ls.setup = default_opts - end - - require("lspconfig")["null-ls"].setup(lvim.lsp.null_ls.setup) + null_ls.setup(vim.tbl_deep_extend("force", default_opts, lvim.lsp.null_ls.setup)) end return M diff --git a/lua/lvim/lsp/null-ls/linters.lua b/lua/lvim/lsp/null-ls/linters.lua index 6a793d26..67e530a9 100644 --- a/lua/lvim/lsp/null-ls/linters.lua +++ b/lua/lvim/lsp/null-ls/linters.lua @@ -12,26 +12,18 @@ local is_registered = function(name) return require("null-ls.sources").is_registered(query) end -function M.list_registered_providers(filetype) +function M.list_registered(filetype) local null_ls_methods = require "null-ls.methods" local linter_method = null_ls_methods.internal["DIAGNOSTICS"] local registered_providers = services.list_registered_providers_names(filetype) return registered_providers[linter_method] or {} end -function M.list_available(filetype) - local linters = {} - local tbl = require "lvim.utils.table" - for _, provider in pairs(null_ls.builtins.diagnostics) do - if tbl.contains(provider.filetypes or {}, function(ft) - return ft == "*" or ft == filetype - end) then - table.insert(linters, provider.name) - end - end - - table.sort(linters) - return linters +function M.list_supported(filetype) + local s = require "null-ls.sources" + local supported_linters = s.get_supported(filetype, "diagnostics") + table.sort(supported_linters) + return supported_linters end function M.list_configured(linter_configs) diff --git a/lua/lvim/lsp/peek.lua b/lua/lvim/lsp/peek.lua index 08345aff..f006f934 100644 --- a/lua/lvim/lsp/peek.lua +++ b/lua/lvim/lsp/peek.lua @@ -47,9 +47,8 @@ local function create_floating_file(location, opts) -- Set some autocmds to close the window vim.api.nvim_command( - "autocmd QuitPre <buffer> ++nested ++once lua pcall(vim.api.nvim_win_close, " .. winnr .. ", true)" + string.format("autocmd %s <buffer> ++once lua pcall(vim.api.nvim_win_close, %d, true)", unpack(close_events), winnr) ) - vim.lsp.util.close_preview_autocmd(close_events, winnr) return bufnr, winnr end @@ -73,10 +72,6 @@ local function preview_location_callback(result) end end -local function preview_location_callback_old_signature(_, _, result) - return preview_location_callback(result) -end - local function preview_location_callback_new_signature(_, result) return preview_location_callback(result) end @@ -136,10 +131,7 @@ function M.Peek(what) else -- Make a new request and then create the new window in the callback local params = vim.lsp.util.make_position_params() - local preview_callback = preview_location_callback_old_signature - if vim.fn.has "nvim-0.5.1" > 0 then - preview_callback = preview_location_callback_new_signature - end + local preview_callback = preview_location_callback_new_signature local success, _ = pcall(vim.lsp.buf_request, 0, "textDocument/" .. what, params, preview_callback) if not success then print( diff --git a/lua/lvim/lsp/providers/sumneko_lua.lua b/lua/lvim/lsp/providers/sumneko_lua.lua index 6585c8c7..7c0030c1 100644 --- a/lua/lvim/lsp/providers/sumneko_lua.lua +++ b/lua/lvim/lsp/providers/sumneko_lua.lua @@ -7,8 +7,6 @@ local opts = { workspace = { library = { [require("lvim.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, @@ -16,4 +14,21 @@ local opts = { }, }, } -return opts + +local lua_dev_loaded, lua_dev = pcall(require, "lua-dev") +if not lua_dev_loaded then + return opts +end + +local dev_opts = { + library = { + vimruntime = true, -- runtime path + types = true, -- full signature, docs and completion of vim.api, vim.treesitter, vim.lsp and others + -- plugins = true, -- installed opt or start plugins in packpath + -- you can also specify the list of plugins to make available as a workspace library + plugins = { "plenary.nvim" }, + }, + lspconfig = opts, +} + +return lua_dev.setup(dev_opts) diff --git a/lua/lvim/lsp/utils.lua b/lua/lvim/lsp/utils.lua index 6d1ed09c..47b1c8ba 100644 --- a/lua/lvim/lsp/utils.lua +++ b/lua/lvim/lsp/utils.lua @@ -76,4 +76,14 @@ function M.get_all_supported_filetypes() return vim.tbl_keys(lsp_installer_filetypes or {}) end +function M.conditional_document_highlight(id) + local client_ok, method_supported = pcall(function() + return vim.lsp.get_client_by_id(id).resolved_capabilities.document_highlight + end) + if not client_ok or not method_supported then + return + end + vim.lsp.buf.document_highlight() +end + return M diff --git a/lua/lvim/plugins.lua b/lua/lvim/plugins.lua index ef53c3d4..0d429ff0 100644 --- a/lua/lvim/plugins.lua +++ b/lua/lvim/plugins.lua @@ -1,38 +1,38 @@ local commit = { barbar = "6e638309efcad2f308eb9c5eaccf6f62b794bbab", - cmp_buffer = "a0fe52489ff6e235d62407f8fa72aef80222040a", + cmp_buffer = "a01cfeca70594f505b2f086501e90fb6c2f2aaaa", cmp_luasnip = "7bd2612533db6863381193df83f9934b373b21e1", cmp_nvim_lsp = "134117299ff9e34adde30a735cd8ca9cf8f3db81", - cmp_nvim_lua = "d276254e7198ab7d00f117e88e223b4bd8c02d21", - cmp_path = "d83839ae510d18530c6d36b662a9e806d4dceb73", - comment = "eb0a84a2ea42858a2bb3cdf5fabe54e7c700555d", + cmp_path = "4d58224e315426e5ac4c5b218ca86cab85f80c79", + comment = "1840a1c085d9f662de4f3cb36fc577a305628b8d", dapinstall = "dd09e9dd3a6e29f02ac171515b8a089fb82bb425", fixcursorhold = "0e4e22d21975da60b0fd2d302285b3b603f9f71e", - friendly_snippets = "4bd6974bd3fcf036a29810bf0570acea55cecfb6", - gitsigns = "a451f97117bd1ede582a6b9db61c387c48d880b6", - lualine = "c4a09735a68c30981c223310848f0649235ec2be", - luasnip = "21bdf396438b98e12d5cd7c0210804e379babae3", - nlsp_settings = "5647a930a0883362b609acb6bfe29cce4202f75d", - null_ls = "fb9e2a64ae8e43c2255025064cfee37dc7d6a752", - nvim_autopairs = "04cd1779f81e9d50d5a116c5dccd054b275bd191", - nvim_cmp = "47d7cfc06abd8661e28dc919882a2fcf01c99729", - nvim_dap = "9b8c27d6dcc21b69834fe9c2d344e49030783390", - nvim_lsp_installer = "4d4677739f52b4aeab8909548b37cc88479c315e", - nvim_lspconfig = "c018b1e92e66b3429a2f167d59211846774f1e3b", - nvim_notify = "ef027e34b618eac42fb0111c1db670ba01793039", - nvim_tree = "f408781a463c2edc3a49091b1bca5a18f790ee3d", - nvim_treesitter = "7474cb06c2be750eae92da51ff7791deb3b21397", + friendly_snippets = "2c96761c3dbeb786875712961fcadb7aa4e16864", + gitsigns = "c18fc65c77abf95ac2e7783b9e7455a7a2fab26c", + lua_dev = "03a44ec6a54b0a025a633978e8541584a02e46d9", + lualine = "a11f6d15d4d8c9ca9105838d3087ac6281bb6acc", + luasnip = "b5a72f1fbde545be101fcd10b70bcd51ea4367de", + nlsp_settings = "1b376a0b7dc60238e835dd0467135ba9a1557ec7", + null_ls = "0327c839c79b1e5087dac7c47dc3c0c2d8ca5d29", + nvim_autopairs = "a9b6b98de3bacacc0c986d9b0673cae6a87c4a41", + nvim_cmp = "1b94aacada96d2a33fef2ecf87748b27a2f50630", + nvim_dap = "a6fa644f9de62c594a8a9cf6f2aaf324b5a6108b", + nvim_lsp_installer = "09e602e1ee7c14687b35a15c229d93d167698ef2", + nvim_lspconfig = "4b21740aae18ecec2d527b79d1072b3b01bb5a2a", + nvim_notify = "15f52efacd169ea26b0f4070451d3ea53f98cd5a", + nvim_tree = "0a2f6b0b6ba558a88c77a6b262af647760e6eca8", + nvim_treesitter = "fa2a6b68aaa6df0187b5bbebe6cbadc120d4a65a", nvim_ts_context_commentstring = "097df33c9ef5bbd3828105e4bee99965b758dc3f", - nvim_web_devicons = "344331467509802e1af200f08ec3da278be5cbba", + nvim_web_devicons = "ac71ca88b1136e1ecb2aefef4948130f31aa40d1", packer = "851c62c5ecd3b5adc91665feda8f977e104162a5", - plenary = "e6267f79481064eee53950571f53cbaafb08417d", + plenary = "a672e11c816d4a91ef01253ba1a2567d20e08e55", popup = "b7404d35d5d3548a82149238289fa71f7f6de4ac", project = "71d0e23dcfc43cfd6bb2a97dc5a7de1ab47a6538", structlog = "6f1403a192791ff1fa7ac845a73de9e860f781f1", - telescope = "80cdb00b221f69348afc4fb4b701f51eb8dd3120", -- see telescope.nvim#1549 + telescope = "1d1da664eb6505c318d405eea3d633c451edc2d8", telescope_fzf_native = "b8662b076175e75e6497c59f3e2799b879d7b954", toggleterm = "265bbff68fbb8b2a5fb011272ec469850254ec9f", - which_key = "0fd9de78fe09215e1b7c6173ff1b0b90c8ed6ec4", + which_key = "312c386ee0eafc925c27869d2be9c11ebdb807eb", } return { @@ -53,6 +53,10 @@ return { "rcarriga/nvim-notify", commit = commit.nvim_notify, disable = not lvim.builtin.notify.active, + config = function() + require("lvim.core.notify").setup() + end, + event = "BufRead", }, { "Tastyep/structlog.nvim", commit = commit.structlog }, @@ -115,8 +119,9 @@ return { commit = commit.cmp_path, }, { - "hrsh7th/cmp-nvim-lua", - commit = commit.cmp_nvim_lua, + "folke/lua-dev.nvim", + module = "lua-dev", + commit = commit.lua_dev, }, -- Autopairs diff --git a/lua/lvim/utils.lua b/lua/lvim/utils.lua new file mode 100644 index 00000000..74bac43f --- /dev/null +++ b/lua/lvim/utils.lua @@ -0,0 +1,107 @@ +local M = {} +local uv = vim.loop + +-- recursive Print (structure, limit, separator) +local function r_inspect_settings(structure, limit, separator) + limit = limit or 100 -- default item limit + separator = separator or "." -- indent string + if limit < 1 then + print "ERROR: Item limit reached." + return limit - 1 + end + if structure == nil then + io.write("-- O", separator:sub(2), " = nil\n") + return limit - 1 + end + local ts = type(structure) + + if ts == "table" then + for k, v in pairs(structure) do + -- replace non alpha keys with ["key"] + if tostring(k):match "[^%a_]" then + k = '["' .. tostring(k) .. '"]' + end + limit = r_inspect_settings(v, limit, separator .. "." .. tostring(k)) + if limit < 0 then + break + end + end + return limit + end + + if ts == "string" then + -- escape sequences + structure = string.format("%q", structure) + end + separator = separator:gsub("%.%[", "%[") + if type(structure) == "function" then + -- don't print functions + io.write("-- lvim", separator:sub(2), " = function ()\n") + else + io.write("lvim", separator:sub(2), " = ", tostring(structure), "\n") + end + return limit - 1 +end + +function M.generate_settings() + -- Opens a file in append mode + local file = io.open("lv-settings.lua", "w") + + -- sets the default output file as test.lua + io.output(file) + + -- write all `lvim` related settings to `lv-settings.lua` file + r_inspect_settings(lvim, 10000, ".") + + -- closes the open file + io.close(file) +end + +--- Returns a table with the default values that are missing. +--- either paramter can be empty. +--@param config (table) table containing entries that take priority over defaults +--@param default_config (table) table contatining default values if found +function M.apply_defaults(config, default_config) + config = config or {} + default_config = default_config or {} + local new_config = vim.tbl_deep_extend("keep", vim.empty_dict(), config) + new_config = vim.tbl_deep_extend("keep", new_config, default_config) + return new_config +end + +--- Checks whether a given path exists and is a file. +--@param path (string) path to check +--@returns (bool) +function M.is_file(path) + local stat = uv.fs_stat(path) + return stat and stat.type == "file" or false +end + +--- Checks whether a given path exists and is a directory +--@param path (string) path to check +--@returns (bool) +function M.is_directory(path) + local stat = uv.fs_stat(path) + return stat and stat.type == "directory" or false +end + +M.join_paths = _G.join_paths + +---Write data to a file +---@param path string can be full or relative to `cwd` +---@param txt string|table text to be written, uses `vim.inspect` internally for tables +---@param flag string used to determine access mode, common flags: "w" for `overwrite` or "a" for `append` +function M.write_file(path, txt, flag) + local data = type(txt) == "string" and txt or vim.inspect(txt) + uv.fs_open(path, flag, 438, function(open_err, fd) + assert(not open_err, open_err) + uv.fs_write(fd, data, -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 + +return M diff --git a/lua/lvim/utils/git.lua b/lua/lvim/utils/git.lua new file mode 100644 index 00000000..73ba7c96 --- /dev/null +++ b/lua/lvim/utils/git.lua @@ -0,0 +1,158 @@ +local M = {} + +local Log = require "lvim.core.log" + +local function git_cmd(opts) + local plenary_loaded, Job = pcall(require, "plenary.job") + if not plenary_loaded then + vim.cmd "packadd plenary.nvim" + end + + opts = opts or {} + opts.cwd = opts.cwd or get_lvim_base_dir() + + local stderr = {} + local stdout, ret = Job + :new({ + command = "git", + args = opts.args, + cwd = opts.cwd, + on_stderr = function(_, data) + table.insert(stderr, data) + end, + }) + :sync() + + if not vim.tbl_isempty(stderr) then + Log:debug(stderr) + end + + if not vim.tbl_isempty(stdout) then + Log:debug(stdout) + end + + return ret, stdout +end + +local function safe_deep_fetch() + local ret, result = git_cmd { args = { "rev-parse", "--is-shallow-repository" } } + if ret ~= 0 then + Log:error "Git fetch failed! Check the log for further information" + return + end + -- git fetch --unshallow will cause an error on a a complete clone + local fetch_mode = result[1] == "true" and "--unshallow" or "--all" + ret = git_cmd { args = { "fetch", fetch_mode } } + if ret ~= 0 then + Log:error "Git fetch failed! Check the log for further information" + return + end + return true +end + +---pulls the latest changes from github +function M.update_base_lvim() + Log:info "Checking for updates" + + local ret = git_cmd { args = { "fetch" } } + if ret ~= 0 then + Log:error "Update failed! Check the log for further information" + return + end + + ret = git_cmd { args = { "diff", "--quiet", "@{upstream}" } } + if ret == 0 then + Log:info "LunarVim is already up-to-date" + return + end + + ret = git_cmd { args = { "merge", "--ff-only", "--progress" } } + if ret ~= 0 then + Log:error "Update failed! Please pull the changes manually instead." + return + end +end + +---Switch Lunarvim to the specified development branch +---@param branch string +function M.switch_lvim_branch(branch) + if not safe_deep_fetch() then + return + end + local ret = git_cmd { args = { "switch", branch } } + if ret ~= 0 then + Log:error "Unable to switch branches! Check the log for further information" + return + end +end + +---Get the current Lunarvim development branch +---@return string|nil +function M.get_lvim_branch() + local ret, branch = git_cmd { args = { "branch", "--show-current" } } + if ret ~= 0 or (not branch or branch[1] == "") then + Log:error "Unable to retrieve the name of the current branch. Check the log for further information" + return + end + return branch[1] +end + +---Get currently checked-out tag of Lunarvim +---@param type string can be "short" +---@return string|nil +function M.get_lvim_tag(type) + type = type or "" + local ret, results = git_cmd { args = { "describe", "--tags" } } + local lvim_full_ver = results[1] or "" + + if ret ~= 0 or string.match(lvim_full_ver, "%d") == nil then + Log:error "Unable to retrieve current tag. Check the log for further information" + return nil + end + if type == "short" then + return vim.fn.split(lvim_full_ver, "-")[1] + else + return string.sub(lvim_full_ver, 1, #lvim_full_ver - 1) + end +end + +---Get the commit hash of currently checked-out commit of Lunarvim +---@param type string can be "short" +---@return string|nil +function M.get_lvim_version(type) + type = type or "" + local branch = M.get_lvim_branch() + if branch == "master" then + return M.get_lvim_tag(type) + end + local ret, log_results = git_cmd { args = { "log", "--pretty=format:%h", "-1" } } + local abbrev_version = log_results[1] or "" + if ret ~= 0 or string.match(abbrev_version, "%d") == nil then + Log:error "Unable to retrieve current version. Check the log for further information" + return nil + end + if type == "short" then + return abbrev_version + end + return branch .. "-" .. abbrev_version +end + +function M.generate_plugins_sha(output) + local list = {} + output = output or "commits.lua" + + local core_plugins = require "lvim.plugins" + for _, plugin in pairs(core_plugins) do + local name = plugin[1]:match "/(%S*)" + local url = "https://github.com/" .. plugin[1] + print("checking: " .. name .. ", at: " .. url) + local retval, latest_sha = git_cmd { args = { "ls-remote", url, "origin", "HEAD" } } + if retval == 0 then + -- replace dashes, remove postfixes and use lowercase + local normalize_name = (name:gsub("-", "_"):gsub("%.%S+", "")):lower() + list[normalize_name] = latest_sha[1]:gsub("\tHEAD", "") + end + end + require("lvim.utils").write_file(output, "local commit = " .. vim.inspect(list), "w") +end +return M diff --git a/lua/lvim/utils/hooks.lua b/lua/lvim/utils/hooks.lua index 9b02b958..ab7dfacd 100644 --- a/lua/lvim/utils/hooks.lua +++ b/lua/lvim/utils/hooks.lua @@ -21,14 +21,14 @@ function M.run_on_packer_complete() require("lvim.plugin-loader").recompile() -- forcefully activate nvim-web-devicons require("nvim-web-devicons").set_up_highlights() + if package.loaded["lspconfig"] then + vim.cmd [[ LspStart ]] + end Log:info "Reloaded configuration" end function M.run_post_reload() Log:debug "Starting post-reload hook" - if package.loaded["lspconfig"] then - vim.cmd [[ LspRestart ]] - end M.reset_cache() require("lvim.plugin-loader").ensure_installed() @@ -68,7 +68,7 @@ function M.run_post_update() -- TODO: add a changelog vim.notify("Update complete", vim.log.levels.INFO) if package.loaded["lspconfig"] then - vim.cmd [[ LspRestart ]] + vim.cmd [[ LspStart ]] end end) end diff --git a/lua/lvim/utils/init.lua b/lua/lvim/utils/init.lua deleted file mode 100644 index cafcf506..00000000 --- a/lua/lvim/utils/init.lua +++ /dev/null @@ -1,211 +0,0 @@ -local utils = {} -local uv = vim.loop - --- recursive Print (structure, limit, separator) -local function r_inspect_settings(structure, limit, separator) - limit = limit or 100 -- default item limit - separator = separator or "." -- indent string - if limit < 1 then - print "ERROR: Item limit reached." - return limit - 1 - end - if structure == nil then - io.write("-- O", separator:sub(2), " = nil\n") - return limit - 1 - end - local ts = type(structure) - - if ts == "table" then - for k, v in pairs(structure) do - -- replace non alpha keys with ["key"] - if tostring(k):match "[^%a_]" then - k = '["' .. tostring(k) .. '"]' - end - limit = r_inspect_settings(v, limit, separator .. "." .. tostring(k)) - if limit < 0 then - break - end - end - return limit - end - - if ts == "string" then - -- escape sequences - structure = string.format("%q", structure) - end - separator = separator:gsub("%.%[", "%[") - if type(structure) == "function" then - -- don't print functions - io.write("-- lvim", separator:sub(2), " = function ()\n") - else - io.write("lvim", separator:sub(2), " = ", tostring(structure), "\n") - end - return limit - 1 -end - -function utils.generate_settings() - -- Opens a file in append mode - local file = io.open("lv-settings.lua", "w") - - -- sets the default output file as test.lua - io.output(file) - - -- write all `lvim` related settings to `lv-settings.lua` file - r_inspect_settings(lvim, 10000, ".") - - -- closes the open file - io.close(file) -end - -function utils.unrequire(m) - package.loaded[m] = nil - _G[m] = nil -end - -function utils.gsub_args(args) - if args == nil or type(args) ~= "table" then - return args - end - local buffer_filepath = vim.fn.fnameescape(vim.api.nvim_buf_get_name(0)) - for i = 1, #args do - args[i] = string.gsub(args[i], "${FILEPATH}", buffer_filepath) - end - return args -end - ---- Returns a table with the default values that are missing. ---- either paramter can be empty. ---@param config (table) table containing entries that take priority over defaults ---@param default_config (table) table contatining default values if found -function utils.apply_defaults(config, default_config) - config = config or {} - default_config = default_config or {} - local new_config = vim.tbl_deep_extend("keep", vim.empty_dict(), config) - new_config = vim.tbl_deep_extend("keep", new_config, default_config) - return new_config -end - ---- Checks whether a given path exists and is a file. ---@param path (string) path to check ---@returns (bool) -function utils.is_file(path) - local stat = uv.fs_stat(path) - return stat and stat.type == "file" or false -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 - -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("lvim.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 - -function utils.generate_plugins_sha(output) - local list = {} - output = output or "commits.lua" - - local function git_cmd(args) - local Job = require "plenary.job" - local stderr = {} - local stdout, ret = Job - :new({ - command = "git", - args = args, - on_stderr = function(_, data) - table.insert(stderr, data) - end, - }) - :sync() - return ret, stdout - end - - local core_plugins = require "lvim.plugins" - for _, plugin in pairs(core_plugins) do - local name = plugin[1]:match "/(%S*)" - local url = "https://github.com/" .. plugin[1] - print("checking: " .. name .. ", at: " .. url) - local retval, latest_sha = git_cmd { "ls-remote", url, "origin", "HEAD" } - if retval == 0 then - -- replace dashes, remove postfixes and use lowercase - local normalize_name = (name:gsub("-", "_"):gsub("%.%S+", "")):lower() - list[normalize_name] = latest_sha[1]:gsub("\tHEAD", "") - end - end - utils.write_file(output, "local commit = " .. vim.inspect(list), "w") -end - -return utils |