diff options
Diffstat (limited to 'lua')
37 files changed, 833 insertions, 436 deletions
| diff --git a/lua/lualine/themes/onedarker.lua b/lua/lualine/themes/onedarker.lua index da99017a..7db197ab 100644 --- a/lua/lualine/themes/onedarker.lua +++ b/lua/lualine/themes/onedarker.lua @@ -15,14 +15,14 @@ local colors = {  return {    normal = { -    a = { fg = colors.fg, bg = colors.blue, gui = "bold" }, +    a = { fg = colors.gray2, bg = colors.blue, gui = "bold" },      b = { fg = colors.fg, bg = colors.bg },      c = { fg = colors.fg, bg = colors.bg },    }, -  insert = { a = { fg = colors.fg, bg = colors.green, gui = "bold" } }, -  visual = { a = { fg = colors.fg, bg = colors.purple, gui = "bold" } }, -  command = { a = { fg = colors.fg, bg = colors.yellow, gui = "bold" } }, -  replace = { a = { fg = colors.fg, bg = colors.red1, gui = "bold" } }, +  insert = { a = { fg = colors.gray2, bg = colors.green, gui = "bold" } }, +  visual = { a = { fg = colors.gray2, bg = colors.purple, gui = "bold" } }, +  command = { a = { fg = colors.gray2, bg = colors.yellow, gui = "bold" } }, +  replace = { a = { fg = colors.gray2, bg = colors.red1, gui = "bold" } },    inactive = {      a = { fg = colors.gray1, bg = colors.bg, gui = "bold" },      b = { fg = colors.gray1, bg = colors.bg }, diff --git a/lua/lvim/bootstrap.lua b/lua/lvim/bootstrap.lua index 74a9bf45..702dfae1 100644 --- a/lua/lvim/bootstrap.lua +++ b/lua/lvim/bootstrap.lua @@ -2,6 +2,7 @@ local M = {}  local uv = vim.loop  local path_sep = uv.os_uname().version:match "Windows" and "\\" or "/" +local in_headless = #vim.api.nvim_list_uis() == 0  ---Join path segments that were passed as input  ---@return string @@ -46,7 +47,7 @@ end  function M:init(base_dir)    self.runtime_dir = get_runtime_dir()    self.config_dir = get_config_dir() -  self.cache_path = get_cache_dir() +  self.cache_dir = get_cache_dir()    self.pack_dir = join_paths(self.runtime_dir, "site", "pack")    self.packer_install_dir = join_paths(self.runtime_dir, "site", "pack", "packer", "start", "packer.nvim")    self.packer_cache_path = join_paths(self.config_dir, "plugin", "packer_compiled.lua") @@ -71,16 +72,13 @@ function M:init(base_dir)      -- TODO: we need something like this: vim.opt.packpath = vim.opt.rtp      vim.cmd [[let &packpath = &runtimepath]] -    vim.cmd("set spellfile=" .. join_paths(self.config_dir, "spell", "en.utf-8.add"))    end -  vim.fn.mkdir(get_cache_dir(), "p") -    -- FIXME: currently unreliable in unit-tests -  if not os.getenv "LVIM_TEST_ENV" then +  if not in_headless then      _G.PLENARY_DEBUG = false      require("lvim.impatient").setup { -      path = vim.fn.stdpath "cache" .. "/lvim_cache", +      path = join_paths(self.cache_dir, "lvim_cache"),        enable_profiling = true,      }    end @@ -174,10 +172,23 @@ end  function M:get_version(type)    type = type or ""    local opts = { cwd = get_lvim_base_dir() } -  local status_ok, results = git_cmd({ "describe", "--tags" }, opts) + +  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 status_ok or string.match(lvim_full_ver, "%d") == nil then +  if not tag_status_ok or string.match(lvim_full_ver, "%d") == nil then      return nil    end    if type == "short" then diff --git a/lua/lvim/config/defaults.lua b/lua/lvim/config/defaults.lua index a20e34e1..a5c81a01 100644 --- a/lua/lvim/config/defaults.lua +++ b/lua/lvim/config/defaults.lua @@ -3,7 +3,12 @@ return {    colorscheme = "onedarker",    line_wrap_cursor_movement = true,    transparent_window = false, -  format_on_save = true, +  format_on_save = { +    ---@usage pattern string pattern used for the autocommand (Default: '*') +    pattern = "*", +    ---@usage timeout number timeout in ms for the format request (Default: 1000) +    timeout = 1000, +  },    keys = {},    builtin = {}, diff --git a/lua/lvim/config/init.lua b/lua/lvim/config/init.lua index 20bc4c81..fba6213d 100644 --- a/lua/lvim/config/init.lua +++ b/lua/lvim/config/init.lua @@ -20,13 +20,13 @@ end  -- Define lvim global variable  function M:init()    if vim.tbl_isempty(lvim or {}) then -    lvim = require "lvim.config.defaults" +    lvim = vim.deepcopy(require "lvim.config.defaults")      local home_dir = vim.loop.os_homedir()      lvim.vsnip_dir = utils.join_paths(home_dir, ".config", "snippets")      lvim.database = { save_location = utils.join_paths(home_dir, ".config", "lunarvim_db"), auto_execute = 1 }    end -  lvim.keys = apply_defaults(lvim.keys, require("lvim.keymappings").get_defaults()) +  require("lvim.keymappings").load_defaults()    local builtins = require "lvim.core.builtins"    builtins.config { user_config_file = user_config_file } @@ -89,8 +89,6 @@ function M:load(config_path)    vim.g.mapleader = (lvim.leader == "space" and " ") or lvim.leader -  local default_keymaps = require("lvim.keymappings").get_defaults() -  lvim.keys = apply_defaults(lvim.keys, default_keymaps)    require("lvim.keymappings").load(lvim.keys)    local settings = require "lvim.config.settings" @@ -100,29 +98,20 @@ end  --- Override the configuration with a user provided one  -- @param config_path The path to the configuration overrides  function M:reload() -  require("lvim.keymappings").clear(lvim.keys) - -  local lvim_modules = {} -  for module, _ in pairs(package.loaded) do -    if module:match "lvim.core" then -      package.loaded[module] = nil -      table.insert(lvim_modules, module) -    end -  end +  package.loaded["lvim.utils.hooks"] = nil +  local _, hooks = pcall(require, "lvim.utils.hooks") +  hooks.run_pre_reload()    M:init()    M:load() +  require("lvim.core.autocmds").configure_format_on_save() +    local plugins = require "lvim.plugins" -  utils.toggle_autoformat()    local plugin_loader = require "lvim.plugin-loader" -  plugin_loader.cache_clear() +    plugin_loader.load { plugins, lvim.plugins } -  vim.cmd ":PackerInstall" -  vim.cmd ":PackerCompile" -  -- vim.cmd ":PackerClean" -  require("lvim.lsp").setup() -  Log:info "Reloaded configuration" +  hooks.run_post_reload()  end  return M diff --git a/lua/lvim/config/settings.lua b/lua/lvim/config/settings.lua index 8db43904..d784ce60 100644 --- a/lua/lvim/config/settings.lua +++ b/lua/lvim/config/settings.lua @@ -43,6 +43,7 @@ M.load_options = function()      wrap = false, -- display lines as one long line      spell = false,      spelllang = "en", +    spellfile = utils.join_paths(get_config_dir(), "spell", "en.utf-8.add"),      scrolloff = 8, -- is one of my fav      sidescrolloff = 8,    } @@ -51,6 +52,8 @@ M.load_options = function()    vim.opt.shortmess:append "c" +  vim.opt.shadafile = utils.join_paths(get_cache_dir(), "lvim.shada") +    for k, v in pairs(default_options) do      vim.opt[k] = v    end diff --git a/lua/lvim/config/supported_languages.lua b/lua/lvim/config/supported_languages.lua index db28df12..ce5bc0db 100644 --- a/lua/lvim/config/supported_languages.lua +++ b/lua/lvim/config/supported_languages.lua @@ -26,6 +26,7 @@ return {    "fennel",    "fish",    "fortran", +  "fsharp",    "gdscript",    "glimmer",    "go", diff --git a/lua/lvim/core/autocmds.lua b/lua/lvim/core/autocmds.lua index 569622be..e4577e63 100644 --- a/lua/lvim/core/autocmds.lua +++ b/lua/lvim/core/autocmds.lua @@ -1,8 +1,14 @@  local M = {} +local Log = require "lvim.core.log"  --- Load the default set of autogroups and autocommands.  function M.load_augroups() -  local user_config_file = vim.fn.resolve(require("lvim.config"):get_user_config_path()) +  local user_config_file = require("lvim.config"):get_user_config_path() + +  if vim.loop.os_uname().version:match "Windows" then +    -- autocmds require forward slashes even on windows +    user_config_file = user_config_file:gsub("\\", "/") +  end    return {      _general_settings = { @@ -58,6 +64,60 @@ function M.load_augroups()    }  end +local get_format_on_save_opts = function() +  local defaults = require("lvim.config.defaults").format_on_save +  -- accept a basic boolean `lvim.format_on_save=true` +  if type(lvim.format_on_save) ~= "table" then +    return defaults +  end + +  return { +    pattern = lvim.format_on_save.pattern or defaults.pattern, +    timeout = lvim.format_on_save.timeout or defaults.timeout, +  } +end + +function M.enable_format_on_save(opts) +  local fmd_cmd = string.format(":silent lua vim.lsp.buf.formatting_sync({}, %s)", opts.timeout_ms) +  M.define_augroups { +    format_on_save = { { "BufWritePre", opts.pattern, fmd_cmd } }, +  } +  Log:debug "enabled format-on-save" +end + +function M.disable_format_on_save() +  M.remove_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 +    M.disable_format_on_save() +  end +end + +function M.toggle_format_on_save() +  if vim.fn.exists "#format_on_save#BufWritePre" == 0 then +    local opts = get_format_on_save_opts() +    M.enable_format_on_save(opts) +  else +    M.disable_format_on_save() +  end +end + +function M.remove_augroup(name) +  if vim.fn.exists("#" .. name) == 1 then +    vim.cmd("au! " .. name) +  end +end +  function M.define_augroups(definitions) -- {{{1    -- Create autocommand groups based on the passed definitions    -- diff --git a/lua/lvim/core/autopairs.lua b/lua/lvim/core/autopairs.lua index 51649790..365d00d5 100644 --- a/lua/lvim/core/autopairs.lua +++ b/lua/lvim/core/autopairs.lua @@ -4,18 +4,45 @@ function M.config()    lvim.builtin.autopairs = {      active = true,      on_config_done = nil, -    ---@usage  -- modifies the function or method delimiter by filetypes +    ---@usage  modifies the function or method delimiter by filetypes      map_char = {        all = "(",        tex = "{",      }, +    ---@usage check bracket in same line +    enable_check_bracket_line = false,      ---@usage check treesitter      check_ts = true,      ts_config = { -      lua = { "string" }, -      javascript = { "template_string" }, +      lua = { "string", "source" }, +      javascript = { "string", "template_string" },        java = false,      }, +    disable_filetype = { "TelescopePrompt", "spectre_panel" }, +    ignored_next_char = string.gsub([[ [%w%%%'%[%"%.] ]], "%s+", ""), +    enable_moveright = true, +    ---@usage disable when recording or executing a macro +    disable_in_macro = false, +    ---@usage add bracket pairs after quote +    enable_afterquote = true, +    ---@usage map the <BS> key +    map_bs = true, +    ---@usage map <c-w> to delete a pair if possible +    map_c_w = false, +    ---@usage disable when insert after visual block mode +    disable_in_visualblock = false, +    ---@usage  change default fast_wrap +    fast_wrap = { +      map = "<M-e>", +      chars = { "{", "[", "(", '"', "'" }, +      pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], "%s+", ""), +      offset = 0, -- Offset from pattern match +      end_key = "$", +      keys = "qwertyuiopzxcvbnmasdfghjkl", +      check_comma = true, +      highlight = "Search", +      highlight_grey = "Comment", +    },    }  end @@ -26,11 +53,19 @@ M.setup = function()    autopairs.setup {      check_ts = lvim.builtin.autopairs.check_ts, +    enable_check_bracket_line = lvim.builtin.autopairs.enable_check_bracket_line,      ts_config = lvim.builtin.autopairs.ts_config, +    disable_filetype = lvim.builtin.autopairs.disable_filetype, +    disable_in_macro = lvim.builtin.autopairs.disable_in_macro, +    ignored_next_char = lvim.builtin.autopairs.ignored_next_char, +    enable_moveright = lvim.builtin.autopairs.enable_moveright, +    enable_afterquote = lvim.builtin.autopairs.enable_afterquote, +    map_c_w = lvim.builtin.autopairs.map_c_w, +    map_bs = lvim.builtin.autopairs.map_bs, +    disable_in_visualblock = lvim.builtin.autopairs.disable_in_visualblock, +    fast_wrap = lvim.builtin.autopairs.fast_wrap,    } -  -- vim.g.completion_confirm_key = "" -    autopairs.add_rule(Rule("$$", "$$", "tex"))    autopairs.add_rules {      Rule("$", "$", { "tex", "latex" }) -- don't add a pair if the next character is % diff --git a/lua/lvim/core/bufferline.lua b/lua/lvim/core/bufferline.lua index ae6542d1..4f7493d6 100644 --- a/lua/lvim/core/bufferline.lua +++ b/lua/lvim/core/bufferline.lua @@ -5,17 +5,13 @@ M.config = function()      active = true,      on_config_done = nil,      keymap = { -      normal_mode = { -        ["<S-l>"] = ":BufferNext<CR>", -        ["<S-h>"] = ":BufferPrevious<CR>", -      }, +      normal_mode = {},      },    }  end  M.setup = function() -  local keymap = require "lvim.keymappings" -  keymap.append_to_defaults(lvim.builtin.bufferline.keymap) +  require("lvim.keymappings").load(lvim.builtin.bufferline.keymap)    if lvim.builtin.bufferline.on_config_done then      lvim.builtin.bufferline.on_config_done() diff --git a/lua/lvim/core/cmp.lua b/lua/lvim/core/cmp.lua index 89159ebb..afad3ead 100644 --- a/lua/lvim/core/cmp.lua +++ b/lua/lvim/core/cmp.lua @@ -301,8 +301,7 @@ M.config = function()    }  end -M.setup = function() -  require("luasnip/loaders/from_vscode").lazy_load() +function M.setup()    require("cmp").setup(lvim.builtin.cmp)  end diff --git a/lua/lvim/core/commands.lua b/lua/lvim/core/commands.lua index 61148889..6997795d 100644 --- a/lua/lvim/core/commands.lua +++ b/lua/lvim/core/commands.lua @@ -16,6 +16,8 @@ M.defaults = {    [[ command! LvimUpdate lua require('lvim.bootstrap').update() ]],    [[ command! LvimSyncCorePlugins lua require('lvim.plugin-loader'):sync_core_plugins() ]],    [[ command! LvimReload lua require('lvim.config'):reload() ]], +  [[ command! LvimToggleFormatOnSave lua require('lvim.core.autocmds').toggle_format_on_save() ]], +  [[ command! LvimVersion lua require('lvim.core.telescope.custom-finders').view_lunarvim_changelog() ]],  }  M.load = function(commands) diff --git a/lua/lvim/core/dashboard.lua b/lua/lvim/core/dashboard.lua index 11053796..0f62d973 100644 --- a/lua/lvim/core/dashboard.lua +++ b/lua/lvim/core/dashboard.lua @@ -58,6 +58,7 @@ M.config = function(config)      footer = { "lunarvim.org" },    } +  lvim.builtin.which_key.mappings[";"] = { "<cmd>Dashboard<CR>", "Dashboard" }  end  M.setup = function() @@ -69,8 +70,6 @@ M.setup = function()    vim.g.dashboard_custom_section = lvim.builtin.dashboard.custom_section -  lvim.builtin.which_key.mappings[";"] = { "<cmd>Dashboard<CR>", "Dashboard" } -    vim.g.dashboard_session_directory = lvim.builtin.dashboard.session_directory    local lvim_site = "lunarvim.org" @@ -85,7 +84,7 @@ M.setup = function()    if lvim_version then      table.insert(footer, 2, "") -    table.insert(footer, 3, "v" .. lvim_version) +    table.insert(footer, 2, lvim_version)    end    local text = require "lvim.interface.text" diff --git a/lua/lvim/core/info.lua b/lua/lvim/core/info.lua index fc87691e..df7b7061 100644 --- a/lua/lvim/core/info.lua +++ b/lua/lvim/core/info.lua @@ -20,6 +20,7 @@ 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 section = {      "Formatters info", @@ -34,6 +35,23 @@ local function make_formatters_info(ft)    return section  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 section = { +    "Code actions info", +    fmt( +      "* Active: %s%s", +      table.concat(registered_actions, "  , "), +      vim.tbl_count(registered_actions) > 0 and "  " or "" +    ), +    fmt("* Supported: %s", str_list(supported_actions)), +  } + +  return section +end +  local function make_linters_info(ft)    local null_linters = require "lvim.lsp.null-ls.linters"    local supported_linters = null_linters.list_available(ft) @@ -120,6 +138,8 @@ function M.toggle_popup(ft)    local linters_info = make_linters_info(ft) +  local code_actions_info = make_code_actions_info(ft) +    local content_provider = function(popup)      local content = {} @@ -136,6 +156,8 @@ function M.toggle_popup(ft)        formatters_info,        { "" },        linters_info, +      { "" }, +      code_actions_info,      } do        vim.list_extend(content, section)      end @@ -150,6 +172,7 @@ function M.toggle_popup(ft)      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")' @@ -159,6 +182,7 @@ function M.toggle_popup(ft)      -- 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")    end    local Popup = require("lvim.interface.popup"):new { diff --git a/lua/lvim/core/log.lua b/lua/lvim/core/log.lua index 9950af28..f51b8af6 100644 --- a/lua/lvim/core/log.lua +++ b/lua/lvim/core/log.lua @@ -1,6 +1,6 @@  local Log = {} -local logfile = string.format("%s/%s.log", vim.fn.stdpath "cache", "lvim") +local logfile = string.format("%s/%s.log", get_cache_dir(), "lvim")  Log.levels = {    TRACE = 1, diff --git a/lua/lvim/core/lualine/components.lua b/lua/lvim/core/lualine/components.lua index 9366df56..9cf67616 100644 --- a/lua/lvim/core/lualine/components.lua +++ b/lua/lvim/core/lualine/components.lua @@ -65,7 +65,7 @@ return {    },    diagnostics = {      "diagnostics", -    sources = { "nvim_lsp" }, +    sources = { "nvim_diagnostic" },      symbols = { error = " ", warn = " ", info = " ", hint = " " },      color = {},      cond = conditions.hide_in_width, @@ -112,9 +112,9 @@ return {        local supported_linters = linters.list_registered_providers(buf_ft)        vim.list_extend(buf_client_names, supported_linters) -      return table.concat(buf_client_names, ", ") +      return "[" .. table.concat(buf_client_names, ", ") .. "]"      end, -    icon = " ", +    -- icon = " ",      color = { gui = "bold" },      cond = conditions.hide_in_width,    }, diff --git a/lua/lvim/core/lualine/conditions.lua b/lua/lvim/core/lualine/conditions.lua index 3ee4fbb8..6e120b26 100644 --- a/lua/lvim/core/lualine/conditions.lua +++ b/lua/lvim/core/lualine/conditions.lua @@ -1,4 +1,4 @@ -local window_width_limit = 80 +local window_width_limit = 70  local conditions = {    buffer_not_empty = function() diff --git a/lua/lvim/core/nvimtree.lua b/lua/lvim/core/nvimtree.lua index 893ddffc..cb91e344 100644 --- a/lua/lvim/core/nvimtree.lua +++ b/lua/lvim/core/nvimtree.lua @@ -6,12 +6,22 @@ function M.config()      active = true,      on_config_done = nil,      setup = { +      disable_netrw = true, +      hijack_netrw = true,        open_on_setup = false, -      auto_close = true, -      open_on_tab = false, -      update_focused_file = { +      ignore_ft_on_setup = { +        "startify", +        "dashboard", +        "alpha", +      }, +      update_to_buf_dir = {          enable = true, +        auto_open = true,        }, +      auto_close = true, +      open_on_tab = false, +      hijack_cursor = false, +      update_cwd = false,        diagnostics = {          enable = true,          icons = { @@ -21,14 +31,36 @@ function M.config()            error = "",          },        }, +      update_focused_file = { +        enable = true, +        update_cwd = true, +        ignore_list = {}, +      }, +      system_open = { +        cmd = nil, +        args = {}, +      }, +      git = { +        enable = true, +        ignore = true, +        timeout = 200, +      },        view = {          width = 30, +        height = 30,          side = "left",          auto_resize = true, +        number = false, +        relativenumber = false,          mappings = {            custom_only = false, +          list = {},          },        }, +      filters = { +        dotfiles = false, +        custom = { ".git", "node_modules", ".cache" }, +      },      },      show_icons = {        git = 1, @@ -37,13 +69,10 @@ function M.config()        folder_arrows = 1,        tree_width = 30,      }, -    ignore = { ".git", "node_modules", ".cache" },      quit_on_open = 0, -    hide_dotfiles = 1,      git_hl = 1, +    disable_window_picker = 0,      root_folder_modifier = ":t", -    allow_resize = 1, -    auto_ignore_ft = { "startify", "dashboard" },      icons = {        default = "",        symlink = "", @@ -65,6 +94,7 @@ function M.config()        },      },    } +  lvim.builtin.which_key.mappings["e"] = { "<cmd>NvimTreeToggle<CR>", "Explorer" }  end  function M.setup() @@ -73,10 +103,9 @@ function M.setup()      Log:error "Failed to load nvim-tree.config"      return    end -  local g = vim.g    for opt, val in pairs(lvim.builtin.nvimtree) do -    g["nvim_tree_" .. opt] = val +    vim.g["nvim_tree_" .. opt] = val    end    -- Implicitly update nvim-tree when project module is active @@ -88,21 +117,21 @@ function M.setup()      vim.g.netrw_banner = false    end +  -- Add useful keymaps    local tree_cb = nvim_tree_config.nvim_tree_callback - -  if not lvim.builtin.nvimtree.setup.view.mappings.list then +  if #lvim.builtin.nvimtree.setup.view.mappings.list == 0 then      lvim.builtin.nvimtree.setup.view.mappings.list = {        { key = { "l", "<CR>", "o" }, cb = tree_cb "edit" },        { key = "h", cb = tree_cb "close_node" },        { key = "v", cb = tree_cb "vsplit" }, +      { key = "C", cb = tree_cb "cd" }, +      { key = "gtf", cb = "<cmd>lua require'lvim.core.nvimtree'.start_telescope('find_files')<cr>" }, +      { key = "gtg", cb = "<cmd>lua require'lvim.core.nvimtree'.start_telescope('live_grep')<cr>" },      }    end -  lvim.builtin.which_key.mappings["e"] = { "<cmd>NvimTreeToggle<CR>", "Explorer" } - -  local tree_view = require "nvim-tree.view" -    -- Add nvim_tree open callback +  local tree_view = require "nvim-tree.view"    local open = tree_view.open    tree_view.open = function()      M.on_open() @@ -138,4 +167,14 @@ function M.change_tree_dir(dir)    end  end +function M.start_telescope(telescope_mode) +  local node = require("nvim-tree.lib").get_node_at_cursor() +  local abspath = node.link_to or node.absolute_path +  local is_folder = node.open ~= nil +  local basedir = is_folder and abspath or vim.fn.fnamemodify(abspath, ":h") +  require("telescope.builtin")[telescope_mode] { +    cwd = basedir, +  } +end +  return M diff --git a/lua/lvim/core/project.lua b/lua/lvim/core/project.lua index e7527440..485137b7 100644 --- a/lua/lvim/core/project.lua +++ b/lua/lvim/core/project.lua @@ -18,7 +18,8 @@ function M.config()      --- **"pattern"** uses vim-rooter like glob pattern matching. Here      --- order matters: if one is not detected, the other is used as fallback. You      --- can also delete or rearangne the detection methods. -    detection_methods = { "lsp", "pattern" }, +    -- detection_methods = { "lsp", "pattern" }, -- NOTE: lsp detection will get annoying with multiple langs in one project +    detection_methods = { "pattern" },      ---@usage patterns used to detect root dir, when **"pattern"** is in detection_methods      patterns = { ".git", "_darcs", ".hg", ".bzr", ".svn", "Makefile", "package.json" }, diff --git a/lua/lvim/core/telescope.lua b/lua/lvim/core/telescope.lua index 147c056c..44aed88b 100644 --- a/lua/lvim/core/telescope.lua +++ b/lua/lvim/core/telescope.lua @@ -37,6 +37,7 @@ function M.config()          "--column",          "--smart-case",          "--hidden", +        "--glob=!.git/",        },        mappings = {          i = { diff --git a/lua/lvim/core/telescope/custom-finders.lua b/lua/lvim/core/telescope/custom-finders.lua index c3347fd0..5ce1485c 100644 --- a/lua/lvim/core/telescope/custom-finders.lua +++ b/lua/lvim/core/telescope/custom-finders.lua @@ -39,12 +39,22 @@ function M.grep_lunarvim_files(opts)    builtin.live_grep(opts)  end +local copy_to_clipboard_action = function(prompt_bufnr) +  local _, action_state = pcall(require, "telescope.actions.state") +  local entry = action_state.get_selected_entry() +  local version = entry.value +  vim.fn.setreg("+", version) +  vim.fn.setreg('"', version) +  vim.notify("Copied " .. version .. " to clipboard", vim.log.levels.INFO) +  actions.close(prompt_bufnr) +end +  function M.view_lunarvim_changelog() -  local opts = {} +  local opts = themes.get_ivy { cwd = get_lvim_base_dir() }    opts.entry_maker = make_entry.gen_from_git_commits(opts)    pickers.new(opts, { -    prompt_title = "LunarVim changelog", +    prompt_title = "~ LunarVim Changelog ~",      finder = finders.new_oneshot_job(        vim.tbl_flatten { @@ -52,22 +62,17 @@ function M.view_lunarvim_changelog()          "log",          "--pretty=oneline",          "--abbrev-commit", -        "--", -        ".",        },        opts      ),      previewer = { -      previewers.git_commit_diff_to_parent.new(opts), -      previewers.git_commit_diff_to_head.new(opts),        previewers.git_commit_diff_as_was.new(opts), -      previewers.git_commit_message.new(opts),      },      --TODO: consider opening a diff view when pressing enter      attach_mappings = function(_, map) -      map("i", "<enter>", actions._close) -      map("n", "<enter>", actions._close) +      map("i", "<enter>", copy_to_clipboard_action) +      map("n", "<enter>", copy_to_clipboard_action)        map("i", "<esc>", actions._close)        map("n", "<esc>", actions._close)        map("n", "q", actions._close) diff --git a/lua/lvim/core/terminal.lua b/lua/lvim/core/terminal.lua index aa6989ec..7eb343ce 100644 --- a/lua/lvim/core/terminal.lua +++ b/lua/lvim/core/terminal.lua @@ -40,53 +40,79 @@ M.config = function()      -- lvim.builtin.terminal.execs = {{}} to overwrite      -- lvim.builtin.terminal.execs[#lvim.builtin.terminal.execs+1] = {"gdb", "tg", "GNU Debugger"}      execs = { -      { "lazygit", "gg", "LazyGit" }, +      -- TODO: this should probably be removed since it's hard to hit <leader>gg within the timeoutlen +      { "lazygit", "<leader>gg", "LazyGit", "float" }, +      { "lazygit", "<c-\\>", "LazyGit", "float" },      },    }  end  M.setup = function()    local terminal = require "toggleterm" -  for _, exec in pairs(lvim.builtin.terminal.execs) do -    require("lvim.core.terminal").add_exec(exec[1], exec[2], exec[3]) -  end    terminal.setup(lvim.builtin.terminal) -  if lvim.builtin.terminal.on_config_done then -    lvim.builtin.terminal.on_config_done(terminal) +  -- setup the default terminal so it's always reachable +  local default_term_opts = { +    cmd = lvim.builtin.terminal.shell, +    keymap = lvim.builtin.terminal.open_mapping, +    label = "Toggle terminal", +    count = 1, +    direction = lvim.builtin.terminal.direction, +    size = lvim.builtin.terminal.size, +  } +  if lvim.builtin.terminal.open_mapping then +    M.add_exec(default_term_opts)    end -end -M.add_exec = function(exec, keymap, name) -  vim.api.nvim_set_keymap( -    "n", -    "<leader>" .. keymap, -    "<cmd>lua require('lvim.core.terminal')._exec_toggle('" .. exec .. "')<CR>", -    { noremap = true, silent = true } -  ) -  lvim.builtin.which_key.mappings[keymap] = name -end +  for i, exec in pairs(lvim.builtin.terminal.execs) do +    local opts = { +      cmd = exec[1], +      keymap = exec[2], +      label = exec[3], +      count = i + 1, +      direction = exec[4] or lvim.builtin.terminal.direction, +      size = lvim.builtin.terminal.size, +    } -M._split = function(inputstr, sep) -  if sep == nil then -    sep = "%s" +    M.add_exec(opts)    end -  local t = {} -  for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do -    table.insert(t, str) + +  if lvim.builtin.terminal.on_config_done then +    lvim.builtin.terminal.on_config_done(terminal)    end -  return t  end -M._exec_toggle = function(exec) -  local binary = M._split(exec)[1] +M.add_exec = function(opts) +  local binary = opts.cmd:match "(%S+)"    if vim.fn.executable(binary) ~= 1 then -    Log:error("Unable to run executable " .. binary .. ". Please make sure it is installed properly.") +    Log:debug("Skipping configuring executable " .. binary .. ". Please make sure it is installed properly.")      return    end + +  local exec_func = string.format( +    "<cmd>lua require('lvim.core.terminal')._exec_toggle({ cmd = '%s', count = %d, direction = '%s'})<CR>", +    opts.cmd, +    opts.count, +    opts.direction +  ) + +  require("lvim.keymappings").load { +    normal_mode = { [opts.keymap] = exec_func }, +    term_mode = { [opts.keymap] = exec_func }, +  } + +  local wk_status_ok, wk = pcall(require, "whichkey") +  if not wk_status_ok then +    return +  end +  wk.register({ [opts.keymap] = { opts.label } }, { mode = "n" }) +  wk.register({ [opts.keymap] = { opts.label } }, { mode = "t" }) +end + +M._exec_toggle = function(opts)    local Terminal = require("toggleterm.terminal").Terminal -  local exec_term = Terminal:new { cmd = exec, hidden = true } -  exec_term:toggle() +  local term = Terminal:new { cmd = opts.cmd, count = opts.count, direction = opts.direction } +  term:toggle(lvim.builtin.terminal.size, opts.direction)  end  ---Toggles a log viewer according to log.viewer.layout_config diff --git a/lua/lvim/core/which-key.lua b/lua/lvim/core/which-key.lua index 254f2ec2..88af028f 100644 --- a/lua/lvim/core/which-key.lua +++ b/lua/lvim/core/which-key.lua @@ -61,7 +61,7 @@ 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 ___comment_gc(vim.fn.visualmode())<CR>", "Comment" }, +      ["/"] = { "<ESC><CMD>lua require('Comment.api').gc(vim.fn.visualmode())<CR>", "Comment" },      },      mappings = {        ["w"] = { "<cmd>w!<CR>", "Save" }, @@ -188,7 +188,7 @@ M.config = function()            "<cmd>lua require('lvim.core.telescope.custom-finders').grep_lunarvim_files()<cr>",            "Grep LunarVim files",          }, -        k = { "<cmd>lua require('lvim.keymappings').print()<cr>", "View LunarVim's default keymappings" }, +        k = { "<cmd>Telescope keymaps<cr>", "View LunarVim's keymappings" },          i = {            "<cmd>lua require('lvim.core.info').toggle_popup(vim.bo.filetype)<cr>",            "Toggle LunarVim Info", diff --git a/lua/lvim/keymappings.lua b/lua/lvim/keymappings.lua index b05d1754..86af1320 100644 --- a/lua/lvim/keymappings.lua +++ b/lua/lvim/keymappings.lua @@ -21,15 +21,124 @@ local mode_adapters = {    command_mode = "c",  } +local defaults = { +  ---@usage change or add keymappings for insert mode +  insert_mode = { +    -- 'jk' for quitting insert mode +    ["jk"] = "<ESC>", +    -- 'kj' for quitting insert mode +    ["kj"] = "<ESC>", +    -- 'jj' for quitting insert mode +    ["jj"] = "<ESC>", +    -- Move current line / block with Alt-j/k ala vscode. +    ["<A-j>"] = "<Esc>:m .+1<CR>==gi", +    -- Move current line / block with Alt-j/k ala vscode. +    ["<A-k>"] = "<Esc>:m .-2<CR>==gi", +    -- navigation +    ["<A-Up>"] = "<C-\\><C-N><C-w>k", +    ["<A-Down>"] = "<C-\\><C-N><C-w>j", +    ["<A-Left>"] = "<C-\\><C-N><C-w>h", +    ["<A-Right>"] = "<C-\\><C-N><C-w>l", +  }, + +  ---@usage change or add keymappings for normal mode +  normal_mode = { +    -- Better window movement +    ["<C-h>"] = "<C-w>h", +    ["<C-j>"] = "<C-w>j", +    ["<C-k>"] = "<C-w>k", +    ["<C-l>"] = "<C-w>l", + +    -- Resize with arrows +    ["<C-Up>"] = ":resize -2<CR>", +    ["<C-Down>"] = ":resize +2<CR>", +    ["<C-Left>"] = ":vertical resize -2<CR>", +    ["<C-Right>"] = ":vertical resize +2<CR>", + +    -- Tab switch buffer +    ["<S-l>"] = ":BufferNext<CR>", +    ["<S-h>"] = ":BufferPrevious<CR>", + +    -- Move current line / block with Alt-j/k a la vscode. +    ["<A-j>"] = ":m .+1<CR>==", +    ["<A-k>"] = ":m .-2<CR>==", + +    -- QuickFix +    ["]q"] = ":cnext<CR>", +    ["[q"] = ":cprev<CR>", +    ["<C-q>"] = ":call QuickFixToggle()<CR>", +  }, + +  ---@usage change or add keymappings for terminal mode +  term_mode = { +    -- Terminal window navigation +    ["<C-h>"] = "<C-\\><C-N><C-w>h", +    ["<C-j>"] = "<C-\\><C-N><C-w>j", +    ["<C-k>"] = "<C-\\><C-N><C-w>k", +    ["<C-l>"] = "<C-\\><C-N><C-w>l", +  }, + +  ---@usage change or add keymappings for visual mode +  visual_mode = { +    -- Better indenting +    ["<"] = "<gv", +    [">"] = ">gv", + +    -- ["p"] = '"0p', +    -- ["P"] = '"0P', +  }, + +  ---@usage change or add keymappings for visual block mode +  visual_block_mode = { +    -- Move selected line / block of text in visual mode +    ["K"] = ":move '<-2<CR>gv-gv", +    ["J"] = ":move '>+1<CR>gv-gv", + +    -- Move current line / block with Alt-j/k ala vscode. +    ["<A-j>"] = ":m '>+1<CR>gv-gv", +    ["<A-k>"] = ":m '<-2<CR>gv-gv", +  }, + +  ---@usage change or add keymappings for command mode +  command_mode = { +    -- navigate tab completion with <c-j> and <c-k> +    -- runs conditionally +    ["<C-j>"] = { 'pumvisible() ? "\\<C-n>" : "\\<C-j>"', { expr = true, noremap = true } }, +    ["<C-k>"] = { 'pumvisible() ? "\\<C-p>" : "\\<C-k>"', { expr = true, noremap = true } }, +  }, +} + +if vim.fn.has "mac" == 1 then +  defaults.normal_mode["<A-Up>"] = defaults.normal_mode["<C-Up>"] +  defaults.normal_mode["<A-Down>"] = defaults.normal_mode["<C-Down>"] +  defaults.normal_mode["<A-Left>"] = defaults.normal_mode["<C-Left>"] +  defaults.normal_mode["<A-Right>"] = defaults.normal_mode["<C-Right>"] +  Log:debug "Activated mac keymappings" +end +  -- Append key mappings to lunarvim's defaults for a given mode  -- @param keymaps The table of key mappings containing a list per mode (normal_mode, insert_mode, ..)  function M.append_to_defaults(keymaps)    local default = M.get_defaults()    lvim.keys = lvim.keys or default    for mode, mappings in pairs(keymaps) do -    lvim.keys[mode] = lvim.keys[mode] or default[mode]      for k, v in pairs(mappings) do -      lvim.keys[mode][k] = v +      defaults[mode][k] = v +    end +  end +end + +-- Unsets all keybindings defined in keymaps +-- @param keymaps The table of key mappings containing a list per mode (normal_mode, insert_mode, ..) +function M.clear(keymaps) +  local default = M.get_defaults() +  for mode, mappings in pairs(keymaps) do +    local translated_mode = mode_adapters[mode] or mode +    for key, _ in pairs(mappings) do +      -- some plugins may override default bindings that the user hasn't manually overriden +      if default[mode][key] ~= nil or (default[translated_mode] ~= nil and default[translated_mode][key] ~= nil) then +        pcall(vim.api.nvim_del_keymap, translated_mode, key) +      end      end    end  end @@ -54,7 +163,7 @@ end  -- @param key The key of keymap  -- @param val Can be form as a mapping or tuple of mapping and user defined opt  function M.set_keymaps(mode, key, val) -  local opt = generic_opts[mode] and generic_opts[mode] or generic_opts_any +  local opt = generic_opts[mode] or generic_opts_any    if type(val) == "table" then      opt = val[2]      val = val[1] @@ -70,7 +179,7 @@ end  -- @param mode The keymap mode, can be one of the keys of mode_adapters  -- @param keymaps The list of key mappings  function M.load_mode(mode, keymaps) -  mode = mode_adapters[mode] and mode_adapters[mode] or mode +  mode = mode_adapters[mode] or mode    for k, v in pairs(keymaps) do      M.set_keymaps(mode, k, v)    end @@ -85,112 +194,18 @@ function M.load(keymaps)    end  end -function M.get_defaults() -  local keys = { -    ---@usage change or add keymappings for insert mode -    insert_mode = { -      -- 'jk' for quitting insert mode -      ["jk"] = "<ESC>", -      -- 'kj' for quitting insert mode -      ["kj"] = "<ESC>", -      -- 'jj' for quitting insert mode -      ["jj"] = "<ESC>", -      -- Move current line / block with Alt-j/k ala vscode. -      ["<A-j>"] = "<Esc>:m .+1<CR>==gi", -      -- Move current line / block with Alt-j/k ala vscode. -      ["<A-k>"] = "<Esc>:m .-2<CR>==gi", -      -- navigation -      ["<A-Up>"] = "<C-\\><C-N><C-w>k", -      ["<A-Down>"] = "<C-\\><C-N><C-w>j", -      ["<A-Left>"] = "<C-\\><C-N><C-w>h", -      ["<A-Right>"] = "<C-\\><C-N><C-w>l", -    }, - -    ---@usage change or add keymappings for normal mode -    normal_mode = { -      -- Better window movement -      ["<C-h>"] = "<C-w>h", -      ["<C-j>"] = "<C-w>j", -      ["<C-k>"] = "<C-w>k", -      ["<C-l>"] = "<C-w>l", - -      -- Resize with arrows -      ["<C-Up>"] = ":resize -2<CR>", -      ["<C-Down>"] = ":resize +2<CR>", -      ["<C-Left>"] = ":vertical resize -2<CR>", -      ["<C-Right>"] = ":vertical resize +2<CR>", - -      -- Tab switch buffer -      ["<S-l>"] = ":BufferNext<CR>", -      ["<S-h>"] = ":BufferPrevious<CR>", - -      -- Move current line / block with Alt-j/k a la vscode. -      ["<A-j>"] = ":m .+1<CR>==", -      ["<A-k>"] = ":m .-2<CR>==", - -      -- QuickFix -      ["]q"] = ":cnext<CR>", -      ["[q"] = ":cprev<CR>", -      ["<C-q>"] = ":call QuickFixToggle()<CR>", -    }, - -    ---@usage change or add keymappings for terminal mode -    term_mode = { -      -- Terminal window navigation -      ["<C-h>"] = "<C-\\><C-N><C-w>h", -      ["<C-j>"] = "<C-\\><C-N><C-w>j", -      ["<C-k>"] = "<C-\\><C-N><C-w>k", -      ["<C-l>"] = "<C-\\><C-N><C-w>l", -    }, - -    ---@usage change or add keymappings for visual mode -    visual_mode = { -      -- Better indenting -      ["<"] = "<gv", -      [">"] = ">gv", - -      -- ["p"] = '"0p', -      -- ["P"] = '"0P', -    }, - -    ---@usage change or add keymappings for visual block mode -    visual_block_mode = { -      -- Move selected line / block of text in visual mode -      ["K"] = ":move '<-2<CR>gv-gv", -      ["J"] = ":move '>+1<CR>gv-gv", - -      -- Move current line / block with Alt-j/k ala vscode. -      ["<A-j>"] = ":m '>+1<CR>gv-gv", -      ["<A-k>"] = ":m '<-2<CR>gv-gv", -    }, - -    ---@usage change or add keymappings for command mode -    command_mode = { -      -- navigate tab completion with <c-j> and <c-k> -      -- runs conditionally -      ["<C-j>"] = { 'pumvisible() ? "\\<C-n>" : "\\<C-j>"', { expr = true, noremap = true } }, -      ["<C-k>"] = { 'pumvisible() ? "\\<C-p>" : "\\<C-k>"', { expr = true, noremap = true } }, -    }, -  } - -  if vim.fn.has "mac" == 1 then -    keys.normal_mode["<A-Up>"] = keys.normal_mode["<C-Up>"] -    keys.normal_mode["<A-Down>"] = keys.normal_mode["<C-Down>"] -    keys.normal_mode["<A-Left>"] = keys.normal_mode["<C-Left>"] -    keys.normal_mode["<A-Right>"] = keys.normal_mode["<C-Right>"] -    Log:debug "Activated mac keymappings" +-- Load the default keymappings +function M.load_defaults() +  M.load(M.get_defaults()) +  lvim.keys = {} +  for idx, _ in pairs(defaults) do +    lvim.keys[idx] = {}    end - -  return keys  end -function M.print(mode) -  print "List of LunarVim's default keymappings (not including which-key)" -  if mode then -    print(vim.inspect(lvim.keys[mode])) -  else -    print(vim.inspect(lvim.keys)) -  end +-- Get the default keymappings +function M.get_defaults() +  return defaults  end  return M diff --git a/lua/lvim/lsp/config.lua b/lua/lvim/lsp/config.lua index ce7ed891..d4e2a741 100644 --- a/lua/lvim/lsp/config.lua +++ b/lua/lvim/lsp/config.lua @@ -4,16 +4,31 @@ return {      signs = {        active = true,        values = { -        { name = "LspDiagnosticsSignError", text = "" }, -        { name = "LspDiagnosticsSignWarning", text = "" }, -        { name = "LspDiagnosticsSignHint", text = "" }, -        { name = "LspDiagnosticsSignInformation", text = "" }, +        { name = "DiagnosticSignError", text = "" }, +        { name = "DiagnosticSignWarn", text = "" }, +        { name = "DiagnosticSignHint", text = "" }, +        { name = "DiagnosticSignInfo", text = "" },        },      },      virtual_text = true,      update_in_insert = false,      underline = true,      severity_sort = true, +    float = { +      focusable = false, +      style = "minimal", +      border = "rounded", +      source = "always", +      header = "", +      prefix = "", +      format = function(d) +        local t = vim.deepcopy(d) +        if d.code then +          t.message = string.format("%s [%s]", t.message, t.code):gsub("1. ", "") +        end +        return t.message +      end, +    },    },    document_highlight = true,    code_lens_refresh = true, @@ -40,10 +55,13 @@ return {    },    null_ls = {      setup = {}, +    config = {},    },    override = {      "angularls",      "ansiblels", +    "ccls", +    "csharp_ls",      "denols",      "ember",      "emmet_ls", @@ -54,10 +72,12 @@ return {      "ltex",      "phpactor",      "pylsp", +    "quick_lint_js",      "rome",      "sorbet",      "sqlls",      "sqls", +    "spectral",      "stylelint_lsp",      "tailwindcss",      "tflint", diff --git a/lua/lvim/lsp/handlers.lua b/lua/lvim/lsp/handlers.lua index 27ce8589..45f73e91 100644 --- a/lua/lvim/lsp/handlers.lua +++ b/lua/lvim/lsp/handlers.lua @@ -9,42 +9,10 @@ function M.setup()      underline = lvim.lsp.diagnostics.underline,      update_in_insert = lvim.lsp.diagnostics.update_in_insert,      severity_sort = lvim.lsp.diagnostics.severity_sort, +    float = lvim.lsp.diagnostics.float,    } -  if vim.fn.has "nvim-0.5.1" > 0 then -    vim.lsp.handlers["textDocument/publishDiagnostics"] = function(_, result, ctx, _) -      local uri = result.uri -      local bufnr = vim.uri_to_bufnr(uri) -      if not bufnr then -        return -      end - -      local diagnostics = result.diagnostics -      local ok, vim_diag = pcall(require, "vim.diagnostic") -      if ok then -        -- FIX: why can't we just use vim.diagnostic.get(buf_id)? -        config.signs = true -        for i, diagnostic in ipairs(diagnostics) do -          local rng = diagnostic.range -          diagnostics[i].lnum = rng["start"].line -          diagnostics[i].end_lnum = rng["end"].line -          diagnostics[i].col = rng["start"].character -          diagnostics[i].end_col = rng["end"].character -        end -        local namespace = vim.lsp.diagnostic.get_namespace(ctx.client_id) - -        vim_diag.set(namespace, bufnr, diagnostics, config) -        if not vim.api.nvim_buf_is_loaded(bufnr) then -          return -        end -        vim_diag.show(namespace, bufnr, diagnostics, config) -      else -        vim.lsp.diagnostic.save(diagnostics, bufnr, ctx.client_id) -        if not vim.api.nvim_buf_is_loaded(bufnr) then -          return -        end -        vim.lsp.diagnostic.display(diagnostics, bufnr, ctx.client_id, config) -      end -    end +  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 @@ -60,27 +28,29 @@ function M.setup()        end        vim.lsp.diagnostic.display(diagnostics, bufnr, client_id, config)      end -  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.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { +      border = lvim.lsp.popup_border, +    }) -local function split_by_chunk(text, chunkSize) -  local s = {} -  for i = 1, #text, chunkSize do -    s[#s + 1] = text:sub(i, i + chunkSize - 1) +    vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { +      border = lvim.lsp.popup_border, +    })    end -  return s  end  function M.show_line_diagnostics() -  -- TODO: replace all this with vim.diagnostic.show_position_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", diff --git a/lua/lvim/lsp/init.lua b/lua/lvim/lsp/init.lua index d00f75c6..68a64d6c 100644 --- a/lua/lvim/lsp/init.lua +++ b/lua/lvim/lsp/init.lua @@ -137,10 +137,10 @@ function M.get_common_opts()  end  local LSP_DEPRECATED_SIGN_MAP = { -  ["LspDiagnosticsSignError"] = "DiagnosticSignError", -  ["LspDiagnosticsSignWarning"] = "DiagnosticSignWarn", -  ["LspDiagnosticsSignHint"] = "DiagnosticSignHint", -  ["LspDiagnosticsSignInformation"] = "DiagnosticSignInfo", +  ["DiagnosticSignError"] = "LspDiagnosticsSignError", +  ["DiagnosticSignWarn"] = "LspDiagnosticsSignWarning", +  ["DiagnosticSignHint"] = "LspDiagnosticsSignHint", +  ["DiagnosticSignInfo"] = "LspDiagnosticsSignInformation",  }  function M.setup() @@ -151,11 +151,11 @@ function M.setup()      return    end -  local is_neovim_nightly = vim.fn.has "nvim-0.5.1" > 0 +  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_nightly and lsp_sign_name then +    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 }) @@ -171,7 +171,7 @@ function M.setup()    require("lvim.lsp.null-ls").setup() -  require("lvim.utils").toggle_autoformat() +  require("lvim.core.autocmds").configure_format_on_save()  end  return M diff --git a/lua/lvim/lsp/manager.lua b/lua/lvim/lsp/manager.lua index dbb7b87f..7a35f1ff 100644 --- a/lua/lvim/lsp/manager.lua +++ b/lua/lvim/lsp/manager.lua @@ -45,48 +45,65 @@ local function buf_try_add(server_name, bufnr)    require("lspconfig")[server_name].manager.try_add_wrapper(bufnr)  end +-- check if the manager autocomd has already been configured since some servers can take a while to initialize +-- this helps guarding against a data-race condition where a server can get configured twice +-- which seems to occur only when attaching to single-files +local function client_is_configured(server_name, ft) +  ft = ft or vim.bo.filetype +  local active_autocmds = vim.split(vim.fn.execute("autocmd FileType " .. ft), "\n") +  for _, result in ipairs(active_autocmds) do +    if result:match(server_name) then +      return true +    end +  end +  return false +end +  ---Setup a language server by providing a name  ---@param server_name string name of the language server  ---@param user_config table [optional] when available it will take predence over any default configurations  function M.setup(server_name, user_config)    vim.validate { name = { server_name, "string" } } -  if lvim_lsp_utils.is_client_active(server_name) then +  if lvim_lsp_utils.is_client_active(server_name) or client_is_configured(server_name) then +    Log:debug(string.format("[%q] is already configured. Ignoring repeated setup call.", server_name))      return    end -  local servers = require "nvim-lsp-installer.servers"    local config = resolve_config(server_name, user_config) + +  local servers = require "nvim-lsp-installer.servers"    local server_available, requested_server = servers.get_server(server_name) -  if server_available then -    local install_notification = false - -    if not requested_server:is_installed() then -      if lvim.lsp.automatic_servers_installation then -        Log:debug "Automatic server installation detected" -        requested_server:install() -        install_notification = true -      else -        Log:debug(requested_server.name .. " is not managed by the automatic installer") -      end -    end +  local is_overridden = vim.tbl_contains(lvim.lsp.override, server_name) -    requested_server:on_ready(function() -      if install_notification then -        vim.notify(string.format("Installation complete for [%s] server", requested_server.name), vim.log.levels.INFO) -      end -      install_notification = false -      requested_server:setup(config) -    end) -  else -    -- since it may not be installed, don't attempt to configure the LSP unless there is a custom provider -    local has_custom_provider, _ = pcall(require, "lvim/lsp/providers/" .. server_name) -    if has_custom_provider then +  if not server_available or is_overridden then +    pcall(function()        require("lspconfig")[server_name].setup(config)        buf_try_add(server_name) +    end) +    return +  end + +  local install_notification = false + +  if not requested_server:is_installed() then +    if lvim.lsp.automatic_servers_installation then +      Log:debug "Automatic server installation detected" +      requested_server:install() +      install_notification = true +    else +      Log:debug(requested_server.name .. " is not managed by the automatic installer")      end    end + +  requested_server:on_ready(function() +    if install_notification then +      vim.notify(string.format("Installation complete for [%s] server", requested_server.name), vim.log.levels.INFO) +    end +    install_notification = false +    requested_server:setup(config) +  end)  end  return M diff --git a/lua/lvim/lsp/null-ls/code_actions.lua b/lua/lvim/lsp/null-ls/code_actions.lua new file mode 100644 index 00000000..ff59fabf --- /dev/null +++ b/lua/lvim/lsp/null-ls/code_actions.lua @@ -0,0 +1,81 @@ +local M = {} + +local null_ls = require "null-ls" +local services = require "lvim.lsp.null-ls.services" +local Log = require "lvim.core.log" + +local METHOD = null_ls.methods.CODE_ACTION + +local is_registered = function(name) +  local query = { +    name = name, +    method = METHOD, +  } +  return require("null-ls.sources").is_registered(query) +end + +function M.list_registered_providers(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 = {}, {} + +  for _, config in ipairs(actions_configs) do +    vim.validate { +      ["config.name"] = { config.name, "string" }, +    } + +    local name = config.name:gsub("-", "_") +    local actor = null_ls.builtins.code_actions[name] + +    if not actor then +      Log:error("Not a valid code_actions: " .. config.name) +      errors[name] = {} -- Add data here when necessary +    elseif is_registered(config.name) then +      Log:trace "Skipping registering  the source more than once" +    else +      local command +      if actor._opts.command then +        command = services.find_command(actor._opts.command) +      end +      if not command and actor._opts.command ~= nil then +        Log:warn("Not found: " .. actor._opts.command) +        errors[name] = {} -- Add data here when necessary +      else +        Log:debug("Using code_actions: " .. (command or config.name)) +        table.insert( +          actors, +          actor.with { +            command = command, -- could be nil +            extra_args = config.args, +            filetypes = config.filetypes, +          } +        ) +      end +    end +  end + +  return { supported = actors, unsupported = errors } +end + +function M.setup(actions_configs) +  if vim.tbl_isempty(actions_configs) then +    return +  end + +  local actions = M.list_configured(actions_configs) +  null_ls.register { sources = actions.supported } +end + +return M diff --git a/lua/lvim/lsp/null-ls/formatters.lua b/lua/lvim/lsp/null-ls/formatters.lua index 20939039..b2e191c5 100644 --- a/lua/lvim/lsp/null-ls/formatters.lua +++ b/lua/lvim/lsp/null-ls/formatters.lua @@ -4,6 +4,14 @@ local null_ls = require "null-ls"  local services = require "lvim.lsp.null-ls.services"  local Log = require "lvim.core.log" +local is_registered = function(name) +  local query = { +    name = name, +    method = require("null-ls").methods.FORMATTING, +  } +  return require("null-ls.sources").is_registered(query) +end +  function M.list_registered_providers(filetype)    local null_ls_methods = require "null-ls.methods"    local formatter_method = null_ls_methods.internal["FORMATTING"] @@ -30,24 +38,29 @@ function M.list_configured(formatter_configs)    local formatters, errors = {}, {}    for _, fmt_config in ipairs(formatter_configs) do -    local formatter_name = fmt_config.exe:gsub("-", "_") -    local formatter = null_ls.builtins.formatting[formatter_name] +    local name = fmt_config.exe:gsub("-", "_") +    local formatter = null_ls.builtins.formatting[name]      if not formatter then        Log:error("Not a valid formatter: " .. fmt_config.exe) -      errors[fmt_config.exe] = {} -- Add data here when necessary +      errors[name] = {} -- Add data here when necessary +    elseif is_registered(fmt_config.exe) then +      Log:trace "Skipping registering  the source more than once"      else        local formatter_cmd = services.find_command(formatter._opts.command)        if not formatter_cmd then          Log:warn("Not found: " .. formatter._opts.command) -        errors[fmt_config.exe] = {} -- Add data here when necessary +        errors[name] = {} -- Add data here when necessary        else          Log:debug("Using formatter: " .. formatter_cmd) -        formatters[fmt_config.exe] = formatter.with { -          command = formatter_cmd, -          extra_args = fmt_config.args, -          filetypes = fmt_config.filetypes, -        } +        table.insert( +          formatters, +          formatter.with { +            command = formatter_cmd, +            extra_args = fmt_config.args, +            filetypes = fmt_config.filetypes, +          } +        )        end      end    end @@ -60,8 +73,8 @@ function M.setup(formatter_configs)      return    end -  local formatters_by_ft = M.list_configured(formatter_configs) -  null_ls.register { sources = formatters_by_ft.supported } +  local formatters = M.list_configured(formatter_configs) +  null_ls.register { sources = formatters.supported }  end  return M diff --git a/lua/lvim/lsp/null-ls/init.lua b/lua/lvim/lsp/null-ls/init.lua index 5e8c6b11..f5e820e8 100644 --- a/lua/lvim/lsp/null-ls/init.lua +++ b/lua/lvim/lsp/null-ls/init.lua @@ -9,7 +9,7 @@ function M:setup()      return    end -  null_ls.config() +  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 diff --git a/lua/lvim/lsp/null-ls/linters.lua b/lua/lvim/lsp/null-ls/linters.lua index ced4bf34..6a793d26 100644 --- a/lua/lvim/lsp/null-ls/linters.lua +++ b/lua/lvim/lsp/null-ls/linters.lua @@ -4,6 +4,14 @@ local null_ls = require "null-ls"  local services = require "lvim.lsp.null-ls.services"  local Log = require "lvim.core.log" +local is_registered = function(name) +  local query = { +    name = name, +    method = require("null-ls").methods.DIAGNOSTICS, +  } +  return require("null-ls.sources").is_registered(query) +end +  function M.list_registered_providers(filetype)    local null_ls_methods = require "null-ls.methods"    local linter_method = null_ls_methods.internal["DIAGNOSTICS"] @@ -21,6 +29,7 @@ function M.list_available(filetype)        table.insert(linters, provider.name)      end    end +    table.sort(linters)    return linters  end @@ -29,24 +38,29 @@ function M.list_configured(linter_configs)    local linters, errors = {}, {}    for _, lnt_config in pairs(linter_configs) do -    local linter_name = lnt_config.exe:gsub("-", "_") -    local linter = null_ls.builtins.diagnostics[linter_name] +    local name = lnt_config.exe:gsub("-", "_") +    local linter = null_ls.builtins.diagnostics[name]      if not linter then        Log:error("Not a valid linter: " .. lnt_config.exe)        errors[lnt_config.exe] = {} -- Add data here when necessary +    elseif is_registered(lnt_config.exe) then +      Log:trace "Skipping registering the source more than once"      else        local linter_cmd = services.find_command(linter._opts.command)        if not linter_cmd then          Log:warn("Not found: " .. linter._opts.command) -        errors[lnt_config.exe] = {} -- Add data here when necessary +        errors[name] = {} -- Add data here when necessary        else          Log:debug("Using linter: " .. linter_cmd) -        linters[lnt_config.exe] = linter.with { -          command = linter_cmd, -          extra_args = lnt_config.args, -          filetypes = lnt_config.filetypes, -        } +        table.insert( +          linters, +          linter.with { +            command = linter_cmd, +            extra_args = lnt_config.args, +            filetypes = lnt_config.filetypes, +          } +        )        end      end    end diff --git a/lua/lvim/lsp/null-ls/services.lua b/lua/lvim/lsp/null-ls/services.lua index 9cb29f49..9151cc39 100644 --- a/lua/lvim/lsp/null-ls/services.lua +++ b/lua/lvim/lsp/null-ls/services.lua @@ -46,15 +46,13 @@ function M.find_command(command)  end  function M.list_registered_providers_names(filetype) -  local u = require "null-ls.utils" -  local c = require "null-ls.config" +  local s = require "null-ls.sources" +  local available_sources = s.get_available(filetype)    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 +  for _, source in ipairs(available_sources) do +    for method in pairs(source.methods) do +      registered[method] = registered[method] or {} +      table.insert(registered[method], source.name)      end    end    return registered diff --git a/lua/lvim/lsp/utils.lua b/lua/lvim/lsp/utils.lua index 7cc8f54f..7659972e 100644 --- a/lua/lvim/lsp/utils.lua +++ b/lua/lvim/lsp/utils.lua @@ -22,11 +22,12 @@ function M.get_active_clients_by_ft(filetype)  end  function M.get_client_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 +    for _, buf_client in pairs(buf_clients) do        if buf_client.name ~= "null-ls" then -        client_id = buf_client.id +        client = buf_client          break        end      end @@ -36,8 +37,6 @@ function M.get_client_capabilities(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 diff --git a/lua/lvim/plugin-loader.lua b/lua/lvim/plugin-loader.lua index c4bd7373..c5220d59 100644 --- a/lua/lvim/plugin-loader.lua +++ b/lua/lvim/plugin-loader.lua @@ -1,12 +1,12 @@  local plugin_loader = {} +local in_headless = #vim.api.nvim_list_uis() == 0 +  local utils = require "lvim.utils"  local Log = require "lvim.core.log"  -- we need to reuse this outside of init()  local compile_path = get_config_dir() .. "/plugin/packer_compiled.lua" -local _, packer = pcall(require, "packer") -  function plugin_loader.init(opts)    opts = opts or {} @@ -18,17 +18,32 @@ function plugin_loader.init(opts)      vim.cmd "packadd packer.nvim"    end +  local log_level = in_headless and "debug" or "warn" +  if lvim.log and lvim.log.level then +    log_level = lvim.log.level +  end + +  local _, packer = pcall(require, "packer")    packer.init {      package_root = package_root,      compile_path = compile_path, -    log = { level = "warn" }, -    git = { clone_timeout = 300 }, +    log = { level = log_level }, +    git = { +      clone_timeout = 300, +      subcommands = { +        -- this is more efficient than what Packer is using +        fetch = "fetch --no-tags --no-recurse-submodules --update-shallow --progress", +      }, +    }, +    max_jobs = 50,      display = {        open_fn = function()          return require("packer.util").float { border = "rounded" }        end,      },    } + +  vim.cmd [[autocmd User PackerComplete lua require('lvim.utils.hooks').run_on_packer_complete()]]  end  -- packer expects a space separated list @@ -58,6 +73,11 @@ end  function plugin_loader.load(configurations)    Log:debug "loading plugins configuration" +  local packer_available, packer = pcall(require, "packer") +  if not packer_available then +    Log:warn "skipping loading plugins until Packer is installed" +    return +  end    local status_ok, _ = xpcall(function()      packer.startup(function(use)        for _, plugins in ipairs(configurations) do @@ -71,6 +91,10 @@ function plugin_loader.load(configurations)      Log:warn "problems detected while loading plugins' configurations"      Log:trace(debug.traceback())    end + +  -- Colorscheme must get called after plugins are loaded or it will break new installs. +  vim.g.colors_name = lvim.colorscheme +  vim.cmd("colorscheme " .. lvim.colorscheme)  end  function plugin_loader.get_core_plugins() @@ -88,4 +112,11 @@ function plugin_loader.sync_core_plugins()    pcall_packer_command("sync", core_plugins)  end +function plugin_loader.ensure_installed() +  plugin_loader.cache_clear() +  local all_plugins = _G.packer_plugins or plugin_loader.get_core_plugins() +  Log:trace(string.format("Syncing core plugins: [%q]", table.concat(all_plugins, ", "))) +  pcall_packer_command("install", all_plugins) +end +  return plugin_loader diff --git a/lua/lvim/plugins.lua b/lua/lvim/plugins.lua index 77ed1ebf..39760397 100644 --- a/lua/lvim/plugins.lua +++ b/lua/lvim/plugins.lua @@ -1,50 +1,53 @@  local commit = { -  packer = "7f62848f3a92eac61ae61def5f59ddb5e2cc6823", -  lsp_config = "903a1fbca91b74e6fbc905366ce38364b9d7ba98", -  nlsp_settings = "29f49afe27b43126d45a05baf3161a28b929f2f1", -  null_ls = "3bf64acca268f3d7e0455501b82cf3f02f38c292", -  fix_cursor_hold = "0e4e22d21975da60b0fd2d302285b3b603f9f71e", -  lsp_installer = "37d9326f4ca4093b04eabdb697fec3764e226f88", -  nvim_notify = "ee79a5e2f8bde0ebdf99880a98d1312da83a3caa", -  structlog = "6f1403a192791ff1fa7ac845a73de9e860f781f1", -  popup = "f91d80973f80025d4ed00380f2e06c669dfda49d", -  plenary = "96e821e8001c21bc904d3c15aa96a70c11462c5f", -  telescope = "078a48db9e0720b07bfcb8b59342c5305a1d1fdc", -  telescope_fzf_native = "59e38e1661ffdd586cb7fc22ca0b5a05c7caf988", -  nvim_cmp = "ca6386854982199a532150cf3bd711395475ebd2", -  friendly_snippets = "94f1d917435c71bc6494d257afa90d4c9449aed2", -  autopairs = "f858ab38b532715dbaf7b2773727f8622ba04322", -  treesitter = "47cfda2c6711077625c90902d7722238a8294982", -  context_commentstring = "159c5b9a2cdb8a8fe342078b7ac8139de76bad62", -  nvim_tree = "f92b7e7627c5a36f4af6814c408211539882c4f3", -  gitsigns = "61a81b0c003de3e12555a5626d66fb6a060d8aca", -  which_key = "d3032b6d3e0adb667975170f626cb693bfc66baa", -  comment = "620445b87a0d1640fac6991f9c3338af8dec1884", -  project = "3a1f75b18f214064515ffba48d1eb7403364cc6a", -  nvim_web_devicons = "ee101462d127ed6a5561ce9ce92bfded87d7d478", -  lualine = "3f5cdc51a08c437c7705e283eebd4cf9fbb18f80",    barbar = "6e638309efcad2f308eb9c5eaccf6f62b794bbab", -  dap = "dd778f65dc95323f781f291fb7c5bf3c17d057b1", -  dap_install = "dd09e9dd3a6e29f02ac171515b8a089fb82bb425", -  toggleterm = "5f9ba91157a25be5ee7395fbc11b1a8f25938365", -  luasnip = "bab7cc2c32fba00776d2f2fc4704bed4eee2d082", -  cmp_luasnip = "16832bb50e760223a403ffa3042859845dd9ef9d", -  cmp_buffer = "d1ca295ce584ec80763a6dc043080874b57ccffc", -  cmp_nvim_lsp = "accbe6d97548d8d3471c04d512d36fa61d0e4be8", -  cmp_path = "97661b00232a2fe145fe48e295875bc3299ed1f7", +  cmp_buffer = "a0fe52489ff6e235d62407f8fa72aef80222040a", +  cmp_luasnip = "75bf6434f175206cd219f9d2bbcae154a009346c", +  cmp_nvim_lsp = "134117299ff9e34adde30a735cd8ca9cf8f3db81",    cmp_nvim_lua = "d276254e7198ab7d00f117e88e223b4bd8c02d21", +  cmp_path = "d83839ae510d18530c6d36b662a9e806d4dceb73", +  comment = "58d489fb7f18c3652adf7e8e1fff9d3281a8fc6a", +  dapinstall = "dd09e9dd3a6e29f02ac171515b8a089fb82bb425", +  fixcursorhold = "0e4e22d21975da60b0fd2d302285b3b603f9f71e", +  friendly_snippets = "4a9516c116f8d3a5766fcb8ac91b176979612d5d", +  gitsigns = "aaf680472187798d5945e39179b540bd3bf80341", +  lualine = "5596c2a25a49ca235613c804169b9063e20b05f5", +  luasnip = "577045e9adf325e58f690f4d4b4a293f3dcec1b3", +  nlsp_settings = "599edc32707f53bd9b0739879f013b3bf162ea4e", +  null_ls = "fb9e2a64ae8e43c2255025064cfee37dc7d6a752", +  nvim_autopairs = "04cd1779f81e9d50d5a116c5dccd054b275bd191", +  nvim_cmp = "af07ff9b7973e95eff9e0275e13fe0350281208b", +  nvim_dap = "3b3027e0ca98775000e1ba727d8f292e821f9f03", +  nvim_lsp_installer = "fcd5d79a7f4966645e9d2f512b85b72f7de0dde2", +  nvim_lspconfig = "e6d95863a336b7e52c92b38c62aa60b469254d14", +  nvim_notify = "ef027e34b618eac42fb0111c1db670ba01793039", +  nvim_tree = "2e33b1654384921ec1cc9656a2018744f3f1ce81", +  nvim_treesitter = "1d66657e6d0f1f8f79ddc48ff1dac9788694cc2d", +  nvim_ts_context_commentstring = "9f5e422e1030e7073e593ad32c5354aa0bcb0176", +  nvim_web_devicons = "344331467509802e1af200f08ec3da278be5cbba", +  packer = "851c62c5ecd3b5adc91665feda8f977e104162a5", +  plenary = "e6267f79481064eee53950571f53cbaafb08417d", +  popup = "b7404d35d5d3548a82149238289fa71f7f6de4ac", +  project = "71d0e23dcfc43cfd6bb2a97dc5a7de1ab47a6538", +  structlog = "6f1403a192791ff1fa7ac845a73de9e860f781f1", +  telescope = "80cdb00b221f69348afc4fb4b701f51eb8dd3120", -- see telescope.nvim#1549 +  telescope_fzf_native = "b8662b076175e75e6497c59f3e2799b879d7b954", +  toggleterm = "265bbff68fbb8b2a5fb011272ec469850254ec9f", +  which_key = "0fd9de78fe09215e1b7c6173ff1b0b90c8ed6ec4",  }  return {    -- Packer can manage itself as an optional plugin    { "wbthomason/packer.nvim", commit = commit.packer }, -  { "neovim/nvim-lspconfig", commit = commit.lsp_config }, +  { "neovim/nvim-lspconfig", commit = commit.nvim_lspconfig },    { "tamago324/nlsp-settings.nvim", commit = commit.nlsp_settings }, -  { "jose-elias-alvarez/null-ls.nvim", commit = commit.null_ls }, -  { "antoinemadec/FixCursorHold.nvim", commit = commit.fix_cursor_hold }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open +  { +    "jose-elias-alvarez/null-ls.nvim", +    commit = commit.null_ls, +  }, +  { "antoinemadec/FixCursorHold.nvim", commit = commit.fixcursorhold }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open    {      "williamboman/nvim-lsp-installer", -    commit = commit.lsp_installer, +    commit = commit.nvim_lsp_installer,    },    {      "rcarriga/nvim-notify", @@ -75,26 +78,31 @@ return {      "hrsh7th/nvim-cmp",      commit = commit.nvim_cmp,      config = function() -      require("lvim.core.cmp").setup() -    end, -    run = function() -      -- cmp's config requires cmp to be installed to run the first time -      if not lvim.builtin.cmp then -        require("lvim.core.cmp").config() +      if lvim.builtin.cmp then +        require("lvim.core.cmp").setup()        end      end, +    requires = { +      "L3MON4D3/LuaSnip", +      "rafamadriz/friendly-snippets", +    },    },    {      "rafamadriz/friendly-snippets",      commit = commit.friendly_snippets, -    -- event = "InsertCharPre", -    -- disable = not lvim.builtin.compe.active,    },    {      "L3MON4D3/LuaSnip", +    config = function() +      require("luasnip/loaders/from_vscode").lazy_load() +    end,      commit = commit.luasnip,    },    { +    "hrsh7th/cmp-nvim-lsp", +    commit = commit.cmp_nvim_lsp, +  }, +  {      "saadparwaiz1/cmp_luasnip",      commit = commit.cmp_luasnip,    }, @@ -103,10 +111,6 @@ return {      commit = commit.cmp_buffer,    },    { -    "hrsh7th/cmp-nvim-lsp", -    commit = commit.cmp_nvim_lsp, -  }, -  {      "hrsh7th/cmp-path",      commit = commit.cmp_path,    }, @@ -118,7 +122,7 @@ return {    -- Autopairs    {      "windwp/nvim-autopairs", -    commit = commit.autopairs, +    commit = commit.nvim_autopairs,      -- event = "InsertEnter",      config = function()        require("lvim.core.autopairs").setup() @@ -129,8 +133,8 @@ return {    -- Treesitter    {      "nvim-treesitter/nvim-treesitter", -    commit = commit.treesitter, -    branch = "0.5-compat", +    commit = commit.nvim_treesitter, +    branch = vim.fn.has "nvim-0.6" == 1 and "master" or "0.5-compat",      -- run = ":TSUpdate",      config = function()        require("lvim.core.treesitter").setup() @@ -138,7 +142,7 @@ return {    },    {      "JoosepAlviste/nvim-ts-context-commentstring", -    commit = commit.context_commentstring, +    commit = commit.nvim_ts_context_commentstring,      event = "BufReadPost",    }, @@ -225,7 +229,7 @@ return {    -- Debugging    {      "mfussenegger/nvim-dap", -    commit = commit.dap, +    commit = commit.nvim_dap,      -- event = "BufWinEnter",      config = function()        require("lvim.core.dap").setup() @@ -236,7 +240,7 @@ return {    -- Debugger management    {      "Pocco81/DAPInstall.nvim", -    commit = commit.dap_install, +    commit = commit.dapinstall,      -- event = "BufWinEnter",      -- event = "BufRead",      disable = not lvim.builtin.dap.active, diff --git a/lua/lvim/utils/hooks.lua b/lua/lvim/utils/hooks.lua index 0fe4a7fd..9b02b958 100644 --- a/lua/lvim/utils/hooks.lua +++ b/lua/lvim/utils/hooks.lua @@ -1,42 +1,75 @@  local M = {} -local plugin_loader = require "lvim.plugin-loader"  local Log = require "lvim.core.log"  local in_headless = #vim.api.nvim_list_uis() == 0  function M.run_pre_update()    Log:debug "Starting pre-update hook" -  _G.__luacache.clear_cache() -  vim.cmd "LspStop" +  if package.loaded["lspconfig"] then +    vim.cmd [[ LspStop ]] +  end +end + +function M.run_pre_reload() +  Log:debug "Starting pre-reload hook" +  if package.loaded["lspconfig"] then +    vim.cmd [[ LspStop ]] +  end +end + +function M.run_on_packer_complete() +  require("lvim.plugin-loader").recompile() +  -- forcefully activate nvim-web-devicons +  require("nvim-web-devicons").set_up_highlights() +  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()  end  ---Reset any startup cache files used by Packer and Impatient  ---It also forces regenerating any template ftplugin files  ---Tip: Useful for clearing any outdated settings  function M.reset_cache() -  _G.__luacache.clear_cache() -  require("lvim.plugin-loader").recompile() -  package.loaded["lvim.lsp.templates"] = nil - -  Log:debug "Re-generatring ftplugin template files" +  local impatient = _G.__luacache +  if impatient then +    impatient.clear_cache() +  end +  local lvim_modules = {} +  for module, _ in pairs(package.loaded) do +    if module:match "lvim.core" or module:match "lvim.lsp" then +      package.loaded[module] = nil +      table.insert(lvim_modules, module) +    end +  end +  Log:trace(string.format("Cache invalidated for core modules: { %s }", table.concat(lvim_modules, ", ")))    require("lvim.lsp.templates").generate_templates()  end  function M.run_post_update()    Log:debug "Starting post-update hook" - -  Log:debug "Re-generatring ftplugin template files" -  package.loaded["lvim.lsp.templates"] = nil -  require("lvim.lsp.templates").generate_templates() +  M.reset_cache()    Log:debug "Updating core plugins" -  plugin_loader:sync_core_plugins() +  require("lvim.plugin-loader").ensure_installed()    if not in_headless then      vim.schedule(function() +      if package.loaded["nvim-treesitter"] then +        vim.cmd [[ TSUpdateSync ]] +      end        -- TODO: add a changelog        vim.notify("Update complete", vim.log.levels.INFO) -      vim.cmd "LspRestart" +      if package.loaded["lspconfig"] then +        vim.cmd [[ LspRestart ]] +      end      end)    end  end diff --git a/lua/lvim/utils/init.lua b/lua/lvim/utils/init.lua index cebbe75c..cafcf506 100644 --- a/lua/lvim/utils/init.lua +++ b/lua/lvim/utils/init.lua @@ -1,5 +1,4 @@  local utils = {} -local Log = require "lvim.core.log"  local uv = vim.loop  -- recursive Print (structure, limit, separator) @@ -58,31 +57,6 @@ function utils.generate_settings()    io.close(file)  end --- autoformat -function utils.toggle_autoformat() -  if lvim.format_on_save then -    require("lvim.core.autocmds").define_augroups { -      autoformat = { -        { -          "BufWritePre", -          "*", -          ":silent lua vim.lsp.buf.formatting_sync()", -        }, -      }, -    } -    Log:debug "Format on save active" -  end - -  if not lvim.format_on_save then -    vim.cmd [[ -      if exists('#autoformat#BufWritePre') -        :autocmd! autoformat -      endif -    ]] -    Log:debug "Format on save off" -  end -end -  function utils.unrequire(m)    package.loaded[m] = nil    _G[m] = nil @@ -200,6 +174,38 @@ function utils.log_contains(query)    return false  end -return utils +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 --- TODO: find a new home for these autocommands +return utils | 
