diff options
50 files changed, 1146 insertions, 537 deletions
diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 00000000..74b20dc7 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,22 @@ +name: changelog +on: release + +jobs: + changelog-gen: + name: Generate changelog + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - uses: orhun/git-cliff-action@v1 + with: + config: cliff.toml + args: -vv --latest --strip header -c .github/workflows/cliff.toml + env: + OUTPUT: CHANGELOG.md + + - name: Print the changelog + run: cat "${{ steps.git-cliff.outputs.changelog }}" diff --git a/.github/workflows/cliff.toml b/.github/workflows/cliff.toml new file mode 100644 index 00000000..372ecf3f --- /dev/null +++ b/.github/workflows/cliff.toml @@ -0,0 +1,79 @@ +# configuration file for git-cliff (0.1.0) + +[changelog] +# changelog header +header = """ +# Changelog\n +All notable changes to this project will be documented in this file.\n +""" +# template for the changelog body +# https://tera.netlify.app/docs/#introduction +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}] +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | upper_first }} + {% for commit in commits + | filter(attribute="scope") + | sort(attribute="scope") %} + - _({{commit.scope}})_ {{ commit.message | upper_first }} + {%- if commit.breaking %} + {% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}} + {%- endif -%} + {%- endfor %} + {% for commit in commits %} + {%- if commit.scope -%} + {% else -%} + - {{ commit.message | upper_first }} + {% if commit.breaking -%} + {% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}} + {% endif -%} + {% endif -%} + {% endfor -%} + {% raw %}{% endraw %}\ +{% endfor %}\n +""" +# remove the leading and trailing whitespaces from the template +trim = true +# changelog footer +footer = """ +<!-- generated by git-cliff --> +""" + +[git] +# allow only conventional commits +# https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^build", group = "<!-- 0 --> Packaging"}, + { message = "^feat", group = "<!-- 1 --> Features"}, + { message = "(^bug|^Bug|^fix)", group = "<!-- 2 --> Bugfix"}, + { message = "^refactor", group = "<!-- 3 --> Refactor"}, + { message = "^doc", group = "<!-- 4 --> Documentation"}, + { message = "^revert", group = "<!-- 5 --> Revert"}, + { message = "^perf", group = "<!-- 6 --> Performance"}, + { message = "^chore", group = "<!-- 7 --> Miscellaneous Tasks", skip = true}, + { message = "^ci", group = "<!-- 7 --> Miscellaneous Tasks", skip = true}, + { message = "^test", group = "<!-- 7 --> Miscellaneous Tasks", skip = true}, +] +# filter out the commits that are not matched by commit parsers +filter_commits = false +# glob pattern for matching git tags +tag_pattern = "v[0-9]*" +# regex for skipping tags +skip_tags = "v0.1.0-beta.1" +# regex for ignoring tags +ignore_tags = "" +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" + +[features] +preserve_order = ["serde_json/preserve_order"] diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index 93c776e3..1bae3a10 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -1,5 +1,9 @@ name: "Commit Linter" -on: pull_request +on: + pull_request: + branches: + - "rolling" + jobs: lint-commits: runs-on: ubuntu-latest @@ -13,3 +17,4 @@ jobs: with: configFile: .github/workflows/commitlint.config.js helpURL: https://github.com/LunarVim/LunarVim/blob/rolling/CONTRIBUTING.md#commit-messages + firstParent: true diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f318882d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,66 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [1.0.0-rc] + +### <!-- 1 --> Features + +- _(installer)_ Nicer rsync output (#2067) +- _(terminal)_ Lazygit can now be toggled (#2039) +- Add lualine config for darkplus +- Last updates before 1.0.0 (#1953) +- Support new null-ls (#1955) +- Empty for empty buffers instead of Buffer <#> +- Improved LSP grouping in lualine +- Decrease hide in width limit for lualine +- Add support for fsharp (#2021) +- Add some messages in uninstall.sh (#1945) +- Null-ls code_actions interface (#2008) +- Full compatibility with neovim v0.6 (#2037) +- Multiple enhancements to lvim-reload (#2054) +- Bump plugin versions (#2064) +- Update lsp-installer and lspconfig hashes to enable solidity_ls language server (#2072) + +### <!-- 2 --> Bugfix + +- _(autopairs)_ Add missing configuration entries (#2030) +- _(bootstrap)_ Remove hard-coded spellfile option (#2061) +- _(cmp)_ Revert broken sequential loading (#2002) +- _(installer)_ Better handling of existing files (#2066) +- _(lsp)_ Avoid installing an overridden server (#1981) +- _(lsp)_ Prevent repeated setup call (#2048) +- _(lsp)_ Correct client_id parsing in lvim-info (#2071) +- _(lsp)_ Allow overriding servers with custom providers (#2070) +- _(lualine)_ Change `fg` of section `a` in onedarker (#1909) +- _(null-ls)_ Allow the same linter and formatter (#1968) +- _(nvimtree)_ Update settings (#2001) +- _(nvimtree)_ Restore default mappings + make them customizable (#2007) +- _(nvimtree)_ Handle paths containing spaces (#2027) +- _(plugins)_ Typo of pin commit of `treesitter` (#2046) +- _(terminal)_ Allow disabling the open binding for toggleterm +- _(windows)_ Autocmd requires forward slashes (#1967) +- _(windows)_ Remove redundant `resolve` call (#1974) +- Bump nvim-tree version +- Formatting +- Remove duplicate lint messages +- Allow LunarVim changelog to work outside the lvim directory (#1952) +- Use an indepdent shadafile from neovim (#1910) +- Packersync issue when you have large number of plugins (#1922) +- No idea why this breaks barbar +- Lsp root can get very annoying when working with multiple languages. User is still able to turn it on. +- Update jdtls script +- Correct order for cmp's setup (#1999) +- Dont close if next char is a close pair and no pairs in same line (#2017) +- More accessible changelog (#2019) +- Better default, ignore `.git` in `live_grep` (#2020) +- No restart required when changing colorscheme (#2026) +- No longer treat lazygit missing as an error (#2051) + +### <!-- 3 --> Refactor + +- Deprecate lvim.lang.FOO (#1913) (#1914) +- More configurable format-on-save (#1937) +- Load the default keymaps once (#1965) + +<!-- generated by git-cliff --> @@ -9,7 +9,12 @@ install-neovim-binary: bash ./utils/installer/install-neovim-from-release uninstall: - @echo TODO: this is currently not supported + @echo Starting LunarVim Uninstaller + bash ./utils/installer/uninstall.sh + +generate_plugins_sha: + @echo generating core-plugins latest SHA list + lvim --headless -c 'lua require("lvim.utils").generate_plugins_sha("latest-sha.lua")' -c 'qall' lint: lint-lua lint-sh diff --git a/ftdetect/fsautocomplete.lua b/ftdetect/fsautocomplete.lua new file mode 100644 index 00000000..0b71987e --- /dev/null +++ b/ftdetect/fsautocomplete.lua @@ -0,0 +1,3 @@ +vim.cmd [[ + au BufNewFile,BufRead *.fs,*.fsx,*.fsi set filetype=fsharp +]] @@ -15,9 +15,6 @@ require("lvim.plugin-loader").load { plugins, lvim.plugins } local Log = require "lvim.core.log" Log:debug "Starting LunarVim" -vim.g.colors_name = lvim.colorscheme -- Colorscheme must get called after plugins are loaded or it will break new installs. -vim.cmd("colorscheme " .. lvim.colorscheme) - local commands = require "lvim.core.commands" commands.load(commands.defaults) 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..c5d1ea04 100644 --- a/lua/lvim/core/terminal.lua +++ b/lua/lvim/core/terminal.lua @@ -40,53 +40,78 @@ 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" }, + { "lazygit", "<leader>gg", "LazyGit", "float" }, + { "lazygit", "<c-\\><c-g>", "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..1fbaf3a9 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,13 @@ return { "ltex", "phpactor", "pylsp", + "quick_lint_js", "rome", "sorbet", "sqlls", "sqls", + "solang", + "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/templates.lua b/lua/lvim/lsp/templates.lua index 33c75a6e..3478f4fb 100644 --- a/lua/lvim/lsp/templates.lua +++ b/lua/lvim/lsp/templates.lua @@ -19,8 +19,7 @@ end ---@param server_name string name of a valid language server, e.g. pyright, gopls, tsserver, etc. ---@param dir string the full path to the desired directory function M.generate_ftplugin(server_name, dir) - local has_custom_provider, _ = pcall(require, "lvim/lsp/providers/" .. server_name) - if vim.tbl_contains(lvim.lsp.override, server_name) and not has_custom_provider then + if vim.tbl_contains(lvim.lsp.override, server_name) then return end diff --git a/lua/lvim/lsp/utils.lua b/lua/lvim/lsp/utils.lua index 7cc8f54f..df3846ce 100644 --- a/lua/lvim/lsp/utils.lua +++ b/lua/lvim/lsp/utils.lua @@ -22,22 +22,23 @@ 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 + else + client = vim.lsp.get_client_by_id(tonumber(client_id)) end - if not client_id then + if not client then error "Unable to determine client_id" return end - local client = vim.lsp.get_client_by_id(tonumber(client_id)) - local enabled_caps = {} for capability, status in pairs(client.resolved_capabilities) do if status == true then 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..8ef72bda 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 = "d7b10b13d72d4bf8f7b34779ddc3514bcc26b0f2", + nvim_lspconfig = "2293320aa824e25327c5a10675ae091d1ff83fbc", + 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 diff --git a/utils/bin/jdtls b/utils/bin/jdtls index adfd5e20..a8821580 100755 --- a/utils/bin/jdtls +++ b/utils/bin/jdtls @@ -9,10 +9,10 @@ case Darwin in Linux) - CONFIG="$HOME/.local/share/nvim/lspinstall/java/config_linux" + CONFIG="$HOME/.local/share/nvim/lsp_servers/jdtls/config_linux" ;; Darwin) - CONFIG="$HOME/.local/share/nvim/lspinstall/java/config_mac" + CONFIG="$HOME/.local/share/nvim/lsp_servers/jdtls/config_mac" ;; esac @@ -39,14 +39,14 @@ location of your Java installation." fi # JAR="$HOME/.config/nvim/.language-servers/eclipse.jdt.ls/org.eclipse.jdt.ls.product/target/repository/plugins/org.eclipse.equinox.launcher_*.jar" -JAR="$HOME/.local/share/nvim/lspinstall/java/plugins/org.eclipse.equinox.launcher_*.jar" +JAR="$HOME/.local/share/nvim/lsp_servers/jdtls/plugins/org.eclipse.equinox.launcher_*.jar" GRADLE_HOME=$HOME/gradle "$JAVACMD" \ -Declipse.application=org.eclipse.jdt.ls.core.id1 \ -Dosgi.bundles.defaultStartLevel=4 \ -Declipse.product=org.eclipse.jdt.ls.core.product \ -Dlog.protocol=true \ -Dlog.level=ALL \ - -javaagent:$HOME/.local/share/nvim/lspinstall/java/lombok.jar \ + -javaagent:$HOME/.local/share/nvim/lsp_servers/jdtls/lombok.jar \ -Xms1g \ -Xmx2G \ -jar $(echo "$JAR") \ diff --git a/utils/installer/config.example.lua b/utils/installer/config.example.lua index 8f124ad3..03906ada 100644 --- a/utils/installer/config.example.lua +++ b/utils/installer/config.example.lua @@ -18,7 +18,7 @@ lvim.leader = "space" -- add your own keymapping lvim.keys.normal_mode["<C-s>"] = ":w<cr>" -- unmap a default keymapping --- lvim.keys.normal_mode["<C-Up>"] = "" +-- lvim.keys.normal_mode["<C-Up>"] = false -- edit a default keymapping -- lvim.keys.normal_mode["<C-q>"] = ":q<cr>" diff --git a/utils/installer/install.ps1 b/utils/installer/install.ps1 index c46bbfc2..0823032a 100644 --- a/utils/installer/install.ps1 +++ b/utils/installer/install.ps1 @@ -64,20 +64,8 @@ function main($cliargs) { backup_old_config __add_separator "80" - - if ($cliargs.Contains("--overwrite")) { - Write-Output "!!Warning!! -> Removing all lunarvim related config because of the --overwrite flag" - $answer = Read-Host "Would you like to continue? [y]es or [n]o " - if ("$answer" -ne "y" -and "$answer" -ne "Y") { - exit 1 - } - - foreach ($dir in $__lvim_dirs) { - if (Test-Path "$dir") { - Remove-Item -Force -Recurse "$dir" - } - } - } + + verify_lvim_dirs if (Test-Path "$env:LUNARVIM_RUNTIME_DIR\site\pack\packer\start\packer.nvim") { Write-Output "Packer already installed" @@ -153,7 +141,7 @@ function check_system_deps() { function install_nodejs_deps() { try { check_system_dep "node" - Invoke-Command npm install -g neovim tree-sitter-cli -ErrorAction Break + Invoke-Command npm install -g neovim tree-sitter-cli -ErrorAction Break } catch { print_missing_dep_msg "$dep" @@ -211,6 +199,29 @@ function setup_shim() { Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\bin\lvim.ps1" -Destination "$INSTALL_PREFIX\bin\lvim.ps1" -Force } +function verify_lvim_dirs() { + if ($cliargs.Contains("--overwrite")) { + Write-Output "!!Warning!! -> Removing all lunarvim related config because of the --overwrite flag" + $answer = Read-Host "Would you like to continue? [y]es or [n]o " + if ("$answer" -ne "y" -and "$answer" -ne "Y") { + exit 1 + } + + foreach ($dir in $__lvim_dirs) { + if (Test-Path "$dir") { + Remove-Item -Force -Recurse "$dir" + } + } + } + + foreach ($dir in $__lvim_dirs) { + if ((Test-Path "$dir") -eq $false) { + New-Item "$dir" -ItemType Directory + } + } + +} + function setup_lvim() { Write-Output "Installing LunarVim shim" @@ -218,30 +229,26 @@ function setup_lvim() { Write-Output "Preparing Packer setup" - if ((Test-Path "$env:LUNARVIM_CONFIG_DIR") -eq $false) { - New-Item "$env:LUNARVIM_CONFIG_DIR" -ItemType Directory - } - if (Test-Path "$env:LUNARVIM_CONFIG_DIR\config.lua") { Remove-Item -Force "$env:LUNARVIM_CONFIG_DIR\config.lua" } Out-File -FilePath "$env:LUNARVIM_CONFIG_DIR\config.lua" - Write-Output "Packer setup complete" + Write-Output "Packer setup complete" - __add_separator "80" + __add_separator "80" - Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\installer\config.example.lua" "$env:LUNARVIM_CONFIG_DIR\config.lua" + Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\installer\config.example.lua" "$env:LUNARVIM_CONFIG_DIR\config.lua" - $answer = Read-Host $(` - "Would you like to create an alias inside your Powershell profile?`n" +` - "(This enables you to start lvim with the command 'lvim') [y]es or [n]o (default: no)" ) - if ("$answer" -eq "y" -and "$answer" -eq "Y") { - create_alias - } + $answer = Read-Host $(` + "Would you like to create an alias inside your Powershell profile?`n" + ` + "(This enables you to start lvim with the command 'lvim') [y]es or [n]o (default: no)" ) + if ("$answer" -eq "y" -and "$answer" -eq "Y") { + create_alias + } - __add_separator "80" + __add_separator "80" Write-Output "Thank you for installing LunarVim!!" Write-Output "You can start it by running: $INSTALL_PREFIX\bin\lvim.ps1" @@ -267,15 +274,16 @@ function __add_separator($div_width) { } function create_alias { - if($null -eq $(Get-Alias | Select-String "lvim")){ - Add-Content -Path $PROFILE -Value $(-join @('Set-Alias lvim "', "$INSTALL_PREFIX", '\bin\lvim.ps1"')) + if ($null -eq $(Get-Alias | Select-String "lvim")) { + Add-Content -Path $PROFILE -Value $( -join @('Set-Alias lvim "', "$INSTALL_PREFIX", '\bin\lvim.ps1"')) - Write-Output "" - Write-Host 'To use the new alias in this window reload your profile with ". $PROFILE".' -ForegroundColor Yellow + Write-Output "" + Write-Host 'To use the new alias in this window reload your profile with ". $PROFILE".' -ForegroundColor Yellow - }else { - Write-Output "Alias is already set and will not be reset." - } + } + else { + Write-Output "Alias is already set and will not be reset." + } } main "$args" diff --git a/utils/installer/install.sh b/utils/installer/install.sh index e7631999..d420baed 100755 --- a/utils/installer/install.sh +++ b/utils/installer/install.sh @@ -12,9 +12,10 @@ declare -r XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-"$HOME/.config"}" declare -r LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-"$XDG_DATA_HOME/lunarvim"}" declare -r LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-"$XDG_CONFIG_HOME/lvim"}" +declare -r LUNARVIM_BASE_DIR="${LUNARVIM_BASE_DIR:-"$LUNARVIM_RUNTIME_DIR/lvim"}" + # TODO: Use a dedicated cache directory #1256 declare -r LUNARVIM_CACHE_DIR="$XDG_CACHE_HOME/nvim" -declare -r LUNARVIM_PACK_DIR="$LUNARVIM_RUNTIME_DIR/site/pack" declare BASEDIR BASEDIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" @@ -105,28 +106,20 @@ function main() { [ "$answer" != "${answer#[Yy]}" ] && install_rust_deps fi - msg "Backing up old LunarVim configuration" backup_old_config - if [ "$ARGS_OVERWRITE" -eq 1 ]; then - for dir in "${__lvim_dirs[@]}"; do - [ -d "$dir" ] && rm -rf "$dir" - done - fi - - install_packer + verify_lvim_dirs - if [ -e "$LUNARVIM_RUNTIME_DIR/lvim/init.lua" ]; then - update_lvim + if [ "$ARGS_LOCAL" -eq 1 ]; then + link_local_lvim + elif [ -d "$LUNARVIM_BASE_DIR" ]; then + validate_lunarvim_files else - if [ "$ARGS_LOCAL" -eq 1 ]; then - link_local_lvim - else - clone_lvim - fi - setup_lvim + clone_lvim fi + setup_lvim + msg "Thank you for installing LunarVim!!" echo "You can start it by running: $INSTALL_PREFIX/bin/lvim" echo "Do not forget to use a font with glyphs (icons) support [https://github.com/ryanoasis/nerd-fonts]" @@ -177,6 +170,26 @@ function print_missing_dep_msg() { fi } +function check_neovim_min_version() { + # TODO: consider locking the requirement to 0.6+ + local verify_version_cmd='if !has("nvim-0.5.1") | cquit | else | quit | endif' + + # exit with an error if min_version not found + if ! nvim --headless -u NONE -c "$verify_version_cmd"; then + echo "[ERROR]: LunarVim requires at least Neovim v0.5.1 or higher" + exit 1 + fi +} + +function validate_lunarvim_files() { + local verify_version_cmd='if v:errmsg != "" | cquit | else | quit | endif' + if ! "$INSTALL_PREFIX/bin/lvim" --headless -c 'LvimUpdate' -c "$verify_version_cmd" &>/dev/null; then + msg "Removing old installation files" + rm -rf "$LUNARVIM_BASE_DIR" + clone_lvim + fi +} + function check_system_deps() { if ! command -v git &>/dev/null; then print_missing_dep_msg "git" @@ -186,6 +199,7 @@ function check_system_deps() { print_missing_dep_msg "neovim" exit 1 fi + check_neovim_min_version } function __install_nodejs_deps_npm() { @@ -253,15 +267,28 @@ function install_rust_deps() { echo "All Rust dependencies are successfully installed" } +function verify_lvim_dirs() { + if [ "$ARGS_OVERWRITE" -eq 1 ]; then + for dir in "${__lvim_dirs[@]}"; do + [ -d "$dir" ] && rm -rf "$dir" + done + fi + + for dir in "${__lvim_dirs[@]}"; do + mkdir -p "$dir" + done +} + function backup_old_config() { for dir in "${__lvim_dirs[@]}"; do - # we create an empty folder for subsequent commands \ - # that require an existing directory - mkdir -p "$dir" "$dir.bak" + if [ ! -d "$dir" ]; then + continue + fi + mkdir -p "$dir.bak" touch "$dir/ignore" + msg "Backing up old $dir to $dir.bak" if command -v rsync &>/dev/null; then - rsync --archive -hh --partial --progress --cvs-exclude \ - --modify-window=1 "$dir"/ "$dir.bak" + rsync --archive -hh --stats --partial --cvs-exclude "$dir"/ "$dir.bak" else OS="$(uname -s)" case "$OS" in @@ -277,25 +304,13 @@ function backup_old_config() { esac fi done - echo "Backup operation complete" -} - -function install_packer() { - if [ -e "$LUNARVIM_PACK_DIR/packer/start/packer.nvim" ]; then - msg "Packer already installed" - else - if ! git clone --depth 1 "https://github.com/wbthomason/packer.nvim" \ - "$LUNARVIM_PACK_DIR/packer/start/packer.nvim"; then - msg "Failed to clone Packer. Installation failed." - exit 1 - fi - fi + msg "Backup operation complete" } function clone_lvim() { msg "Cloning LunarVim configuration" if ! git clone --branch "$LV_BRANCH" \ - --depth 1 "https://github.com/${LV_REMOTE}" "$LUNARVIM_RUNTIME_DIR/lvim"; then + --depth 1 "https://github.com/${LV_REMOTE}" "$LUNARVIM_BASE_DIR"; then echo "Failed to clone repository. Installation failed." exit 1 fi @@ -305,14 +320,13 @@ function link_local_lvim() { echo "Linking local LunarVim repo" # Detect whether it's a symlink or a folder - if [ -d "$LUNARVIM_RUNTIME_DIR/lvim" ]; then + if [ -d "$LUNARVIM_BASE_DIR" ]; then echo "Removing old installation files" - rm -rf "$LUNARVIM_RUNTIME_DIR/lvim" + rm -rf "$LUNARVIM_BASE_DIR" fi - mkdir -p "$LUNARVIM_RUNTIME_DIR" - echo " - $BASEDIR -> $LUNARVIM_RUNTIME_DIR/lvim" - ln -s -f "$BASEDIR" "$LUNARVIM_RUNTIME_DIR/lvim" + echo " - $BASEDIR -> $LUNARVIM_BASE_DIR" + ln -s -f "$BASEDIR" "$LUNARVIM_BASE_DIR" } function setup_shim() { @@ -351,9 +365,9 @@ function setup_lvim() { setup_shim - echo "Preparing Packer setup" + cp "$LUNARVIM_BASE_DIR/utils/installer/config.example.lua" "$LUNARVIM_CONFIG_DIR/config.lua" - cp "$LUNARVIM_RUNTIME_DIR/lvim/utils/installer/config.example.lua" "$LUNARVIM_CONFIG_DIR/config.lua" + echo "Preparing Packer setup" "$INSTALL_PREFIX/bin/lvim" --headless \ -c 'autocmd User PackerComplete quitall' \ @@ -362,10 +376,6 @@ function setup_lvim() { echo "Packer setup complete" } -function update_lvim() { - "$INSTALL_PREFIX/bin/lvim" --headless +'LvimUpdate' +q -} - function print_logo() { cat <<'EOF' diff --git a/utils/installer/uninstall.sh b/utils/installer/uninstall.sh index 31007984..236d657f 100755 --- a/utils/installer/uninstall.sh +++ b/utils/installer/uninstall.sh @@ -13,8 +13,6 @@ declare -r LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-"$XDG_CONFIG_HOME/lvim"}" # TODO: Use a dedicated cache directory #1256 declare -r LUNARVIM_CACHE_DIR="$XDG_CACHE_HOME/nvim" -LVIM_BIN="$(which lvim 2>/dev/null)" - declare -a __lvim_dirs=( "$LUNARVIM_CONFIG_DIR" "$LUNARVIM_RUNTIME_DIR" @@ -44,15 +42,33 @@ function parse_arguments() { done } -function main() { - parse_arguments "$@" +function remove_lvim_dirs() { for dir in "${__lvim_dirs[@]}"; do rm -rf "$dir" if [ "$ARGS_REMOVE_BACKUPS" -eq 1 ]; then rm -rf "$dir.bak" fi done - rm -f "$LVIM_BIN" +} + +function remove_lvim_bin() { + local legacy_bin="/usr/local/bin/lvim " + if [ -x "$legacy_bin" ]; then + echo "Error! Unable to remove $legacy_bin without elevation. Please remove manually." + exit 1 + fi + + lvim_bin="$(command -v lvim 2>/dev/null)" + rm -f "$lvim_bin" +} + +function main() { + parse_arguments "$@" + echo "Removing LunarVim binary..." + remove_lvim_bin + echo "Removing LunarVim directories..." + remove_lvim_dirs + echo "Uninstalled LunarVim!" } main "$@" |