diff options
| author | kylo252 <[email protected]> | 2022-01-03 15:49:07 +0100 | 
|---|---|---|
| committer | kylo252 <[email protected]> | 2022-01-03 15:49:07 +0100 | 
| commit | e5aa8be8ce54097e4a34220cb2aad114e70f209b (patch) | |
| tree | 15e0a3017358b15a0656b6d1f98d2638ae572095 | |
| parent | 427ad868d404a254dcbc7d3950946dae0cf205de (diff) | |
| parent | 21b41688ee8c5056ffbb2b07df141ce1ccb4b213 (diff) | |
Merge branch 'rolling'
47 files changed, 858 insertions, 866 deletions
| diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 219f903b..ebcfa911 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,7 +3,7 @@ blank_issues_enabled: true  contact_links:    - name: Matrix community      url: https://matrix.to/#/#atmachine-neovim:matrix.org -    about: Please ask and answer questions on Matrix. +    about: Ask and discuss about LunarVim on Matrix.    - name: Discord community -    url: https://discord.gg/Xb9B4Ny -    about: Please ask and answer questions on Discord. +    url: https://discord.com/invite/sbDcEmJHww +    about: Ask and discuss about LunarVim on Discord. diff --git a/.github/ISSUE_TEMPLATE/feature-form.yaml b/.github/ISSUE_TEMPLATE/feature-form.yaml index cfd0793b..1ae52f4a 100644 --- a/.github/ISSUE_TEMPLATE/feature-form.yaml +++ b/.github/ISSUE_TEMPLATE/feature-form.yaml @@ -1,34 +1,25 @@  name: Feature Request  description: Suggest an idea for improving this project -title: "[Feature]: "  labels: [enhancement] -# assignees: -#   - ChristianChiarulli  +  body:    - type: markdown      attributes: -      value: | -        Thank you for helping us improve ! +      value: Thank you for helping us improve! +    - type: textarea      id: motivation      attributes: -      label: Feature motivation -      description: A clear and concise description of the problem or missing capability -      placeholder: | -        I am always frustrated when ... +      label: Feature Description +      placeholder: What is the expected behavior of this new feature?      validations:        required: true    - type: textarea -    id: solution -    attributes: -      label: Describe the expected solution -  - type: textarea      id: alternatives      attributes: -      label: Describe the alternatives you've considered -      description: Let us know about other solutions you've tried or researched +      label: Describe the alternatives you have considered    - type: textarea      id: additional-context      attributes: -      label: Additional context +      label: Support information        description: If applicable, add screenshots or link related issues diff --git a/.github/ISSUE_TEMPLATE/general-issue-form.yaml b/.github/ISSUE_TEMPLATE/general-issue-form.yaml index 50a8e210..56fbc1dc 100644 --- a/.github/ISSUE_TEMPLATE/general-issue-form.yaml +++ b/.github/ISSUE_TEMPLATE/general-issue-form.yaml @@ -1,14 +1,14 @@  name: General Issue  description: File a bug report -title: "[Bug]: "  labels: [bug] -# assignees: -#   - ChristianChiarulli  +  body:    - type: markdown      attributes:        value: | -        Thank you for helping us improve ! +        _Before reporting:_ search [existing issues](https://github.com/lunarvim/lunarvim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [Troubleshooting guide](https://www.lunarvim.org/troubleshooting).  +        If you need real-time help, join us on Discord. Thank you for helping us improve! +    - type: textarea      id: problem-description      attributes: @@ -26,13 +26,25 @@ body:      id: lunar-vim-version      attributes:        label: LunarVim version +      placeholder: | +        output of :LvimVersion      validations:        required: true    - type: input      id: nvim-version      attributes: -      label: Neovim version (>= 0.5) -      placeholder: nvim --version +      label: Neovim version (>= 0.6) +      description: "Output of `nvim --version`" +      placeholder: | +        NVIM v0.6.0-dev+209-g0603eba6e +        Build type: Release +        LuaJIT 2.1.0-beta3 +    validations: +      required: true +  - type: input +    attributes: +      label: "Operating system/version" +      placeholder: "macOS 11.5"      validations:        required: true    - type: textarea @@ -40,24 +52,14 @@ body:      attributes:        label: Relevant log output        placeholder: | -        nvim -v          :checkhealth          :messages +        :e $LUNARVIM_CACHE/DIR/lvim.log        render: shell +    validations: +      required: true    - type: textarea      id: screenshots      attributes:        label: Screenshots        description: If applicable, add screenshots to help explain your problem -  - type: checkboxes -    id: checks -    attributes: -      label: I have -      options: -      - label: Read the readme -        required: true -      - label: Read the wiki -        required: true -      - label: Searched for similar issues -        required: true - diff --git a/.github/ISSUE_TEMPLATE/lsp-issue-form.yaml b/.github/ISSUE_TEMPLATE/lsp-issue-form.yaml index 2fabeee6..c0743651 100644 --- a/.github/ISSUE_TEMPLATE/lsp-issue-form.yaml +++ b/.github/ISSUE_TEMPLATE/lsp-issue-form.yaml @@ -1,80 +1,87 @@  name: LSP Issue  description: File a LSP related bug report -title: "[Bug]: "  labels: [bug, lsp] -# assignees: -#   - ChristianChiarulli  +  body:    - type: markdown      attributes:        value: | -        Thank you for helping us improve ! +        _Before reporting:_ search [existing issues](https://github.com/lunarvim/lunarvim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [Troubleshooting guide](https://www.lunarvim.org/troubleshooting).  +        If you need real-time help, join us on Discord. Thank you for helping us improve! +    - type: textarea      id: problem-description      attributes:        label: Problem description -      description: Also tell us, what did you expect to happen? -      placeholder: | -        Steps to reproduce the behavior: -        1. Go to '...' -        2. Click on '....' -        3. Scroll down to '....' -        4. See error +      description: "A short description of the problem you are reporting."      validations:        required: true -  - type: checkboxes -    id: generic-checks -    attributes: -      label: Check the following -      options: -      - label: I am in a git managed directory -        required: true -      - label: I restarted Neovim after running :LspInstall -        required: true -      - label: I have a valid language configuration (~/.config/lvim/ftplugin/) -        required: true -      - label: I checked the options (~/.config/lvim/config.lua) -        required: true -      - label: The programs specified by the config are installed    - type: input      id: lunar-vim-version      attributes:        label: LunarVim version +      placeholder: | +        output of :LvimVersion      validations:        required: true    - type: input      id: nvim-version      attributes: -      label: Neovim version (>= 0.5) -      placeholder: nvim --version +      label: Neovim version (>= 0.6) +      description: "Output of `nvim --version`" +      placeholder: | +        NVIM v0.6.0-dev+209-g0603eba6e +        Build type: Release +        LuaJIT 2.1.0-beta3 +    validations: +      required: true +  - type: input +    attributes: +      label: "Operating system/version" +      placeholder: "macOS 11.5" +    validations: +      required: true +  - type: input +    attributes: +      label: "Affected language servers" +      description: "If this issue is specific to one or more language servers, list them here. If not, write 'all'." +      placeholder: "tsserver"      validations:        required: true    - type: textarea +    attributes: +      label: "Steps to reproduce" +      description: "Steps to reproduce using the minimal config." +      placeholder: | +        1. `nvim -u ~/.local/share/lunarvim/lvim/tests/minimal_lsp.lua` +        2. ... +  - type: textarea +    attributes: +      label: "Actual behavior" +      description: "Observed behavior." +    validations: +      required: true +  - type: textarea +    attributes: +      label: "Expected behavior" +      description: "A description of the behavior you expected." +  - type: textarea      id: logs      attributes: -      label: Relevant log output +      label: log and support info        placeholder: | -        :echo &ft          :LspInfo - -        :LspStart <language> +        :LvimInfo          :messages          :checkhealth -        grep ERROR ~/.cache/nvim/lsp.log +        :e $LUNARVIM_CACHE/DIR/lsp.log +        :e $LUNARVIM_CACHE/DIR/lvim.log +        :e $LUNARVIM_CACHE/DIR/log        render: shell +    validations: +      required: true    - type: textarea      id: screenshots      attributes:        label: Screenshots        description: If applicable, add screenshots to help explain your problem -  - type: checkboxes -    id: documentation-checks -    attributes: -      label: I have -      options: -      - label: Read the readme -        required: true -      - label: Read the wiki -        required: true -      - label: Searched for similar issues -        required: true diff --git a/.luacheckrc b/.luacheckrc index 71745e48..136e2326 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -23,8 +23,7 @@ stds.nvim = {      "get_config_dir",      "get_cache_dir",      "get_lvim_base_dir", -    "get_version", -    -- vim = { fields = { "cmd", "api", "fn", "o" } }, +    "require_clean",    },  }  std = "lua51+nvim" @@ -1,20 +1,24 @@  SHELL := /bin/bash  install: -	@echo Starting LunarVim Installer +	@echo starting LunarVim installer  	bash ./utils/installer/install.sh +install-bin: +	@echo starting LunarVim bin-installer +	bash ./utils/installer/install_bin.sh +  install-neovim-binary: -	@echo Installing Neovim from github releases +	@echo installing Neovim from github releases  	bash ./utils/installer/install-neovim-from-release  uninstall: -	@echo Starting LunarVim Uninstaller +	@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' +	lvim --headless -c 'lua require("lvim.utils.git").generate_plugins_sha("latest-sha.lua")' -c 'qall'  lint: lint-lua lint-sh @@ -30,7 +34,7 @@ style-lua:  	stylua --config-path .stylua.toml --check .  style-sh: -	shfmt -f . | grep -v jdtls | xargs shfmt -i 2 -ci -l -d +	shfmt -f . | grep -v jdtls | xargs shfmt -i 2 -ci -bn -l -d  test:  	bash ./utils/bin/test_runner.sh "$(TEST)" @@ -26,7 +26,7 @@ You can find all the documentation for LunarVim at [lunarvim.org](https://www.lu  ## Install In One Command! -Make sure you have the release version of Neovim (0.5). +Make sure you have the release version of Neovim (0.6).  ```bash  bash <(curl -s https://raw.githubusercontent.com/lunarvim/lunarvim/master/utils/installer/install.sh) @@ -70,6 +70,7 @@ lvim.keys.normal_mode["<C-s>"] = ":w<cr>"  -- Configure builtin plugins  lvim.builtin.dashboard.active = true +lvim.builtin.notify.active = true  lvim.builtin.terminal.active = true  -- Treesitter parsers change this to a table of the languages you want i.e. {"java", "python", javascript} @@ -129,6 +130,7 @@ lvim.plugins = {  ## Breaking changes  - `lvim.lang.FOO` is no longer supported. Refer to <https://www.lunarvim.org/languages> for up-to-date instructions. +- `lvim.lsp.popup_border` has been deprecated in favor of `lvim.lsp.float.border` and `lvim.lsp.diagnostics.float.border`.  ## Resources diff --git a/lua/lvim/bootstrap.lua b/lua/lvim/bootstrap.lua index 702dfae1..2300c753 100644 --- a/lua/lvim/bootstrap.lua +++ b/lua/lvim/bootstrap.lua @@ -1,5 +1,13 @@  local M = {} +if vim.fn.has "nvim-0.6" ~= 1 then +  vim.notify("Please upgrade your Neovim base installation. Lunarvim requires v0.6+", vim.log.levels.WARN) +  vim.wait(5000, function() +    return false +  end) +  vim.cmd "cquit" +end +  local uv = vim.loop  local path_sep = uv.os_uname().version:match "Windows" and "\\" or "/"  local in_headless = #vim.api.nvim_list_uis() == 0 @@ -11,6 +19,16 @@ function _G.join_paths(...)    return result  end +---Require a module in protected mode without relying on its cached value +---@param module string +---@return any +function _G.require_clean(module) +  package.loaded[module] = nil +  _G[module] = nil +  local _, requested = pcall(require, module) +  return requested +end +  ---Get the full path to `$LUNARVIM_RUNTIME_DIR`  ---@return string  function _G.get_runtime_dir() @@ -96,106 +114,9 @@ end  ---Update LunarVim  ---pulls the latest changes from github and, resets the startup cache  function M:update() -  package.loaded["lvim.utils.hooks"] = nil -  local _, hooks = pcall(require, "lvim.utils.hooks") -  hooks.run_pre_update() -  M:update_repo() -  hooks.run_post_update() -end - -local function git_cmd(subcmd, opts) -  local Job = require "plenary.job" -  local Log = require "lvim.core.log" -  local args = { "-C", opts.cwd } -  vim.list_extend(args, subcmd) - -  local stderr = {} -  local stdout, ret = Job -    :new({ -      command = "git", -      args = args, -      cwd = opts.cwd, -      on_stderr = function(_, data) -        table.insert(stderr, data) -      end, -    }) -    :sync() - -  if not vim.tbl_isempty(stderr) then -    Log:debug(stderr) -  end - -  if not vim.tbl_isempty(stdout) then -    Log:debug(stdout) -  end - -  return ret, stdout -end - ----pulls the latest changes from github -function M:update_repo() -  local Log = require "lvim.core.log" -  local sub_commands = { -    fetch = { "fetch" }, -    diff = { "diff", "--quiet", "@{upstream}" }, -    merge = { "merge", "--ff-only", "--progress" }, -  } -  local opts = { -    cwd = get_lvim_base_dir(), -  } -  Log:info "Checking for updates" - -  local ret = git_cmd(sub_commands.fetch, opts) -  if ret ~= 0 then -    Log:error "Update failed! Check the log for further information" -    return -  end - -  ret = git_cmd(sub_commands.diff, opts) - -  if ret == 0 then -    Log:info "LunarVim is already up-to-date" -    return -  end - -  ret = git_cmd(sub_commands.merge, opts) - -  if ret ~= 0 then -    Log:error "Update failed! Please pull the changes manually instead." -    return -  end -end - ----Get currently installed version of LunarVim ----@param type string can be "short" ----@return string -function M:get_version(type) -  type = type or "" -  local opts = { cwd = get_lvim_base_dir() } - -  local _, branch = git_cmd({ "branch", "--show-current" }, opts) - -  local is_on_master = branch == "master" -  if not is_on_master then -    local log_status_ok, log_results = git_cmd({ "log", "--pretty=format:%h", "-1" }, opts) -    local abbrev_version = log_results[1] or "" -    if not log_status_ok or string.match(abbrev_version, "%d") == nil then -      return nil -    end -    return "dev-" .. abbrev_version -  end - -  local tag_status_ok, results = git_cmd({ "describe", "--tags" }, opts) -  local lvim_full_ver = results[1] or "" - -  if not tag_status_ok or string.match(lvim_full_ver, "%d") == nil then -    return nil -  end -  if type == "short" then -    return vim.fn.split(lvim_full_ver, "-")[1] -  else -    return string.sub(lvim_full_ver, 1, #lvim_full_ver - 1) -  end +  require_clean("lvim.utils.hooks").run_pre_update() +  require_clean("lvim.utils.git").update_base_lvim() +  require_clean("lvim.utils.hooks").run_post_update()  end  return M diff --git a/lua/lvim/config/init.lua b/lua/lvim/config/init.lua index 9b6d36f0..145173b1 100644 --- a/lua/lvim/config/init.lua +++ b/lua/lvim/config/init.lua @@ -66,6 +66,11 @@ local function handle_deprecated_settings()        deprecation_notice(string.format("lvim.lang.%s", lang))      end    end + +  -- lvim.lsp.popup_border +  if vim.tbl_contains(vim.tbl_keys(lvim.lsp), "popup_border") then +    deprecation_notice "lvim.lsp.popup_border" +  end  end  --- Override the configuration with a user provided one @@ -97,9 +102,7 @@ end  --- Override the configuration with a user provided one  -- @param config_path The path to the configuration overrides  function M:reload() -  package.loaded["lvim.utils.hooks"] = nil -  local _, hooks = pcall(require, "lvim.utils.hooks") -  hooks.run_pre_reload() +  require_clean("lvim.utils.hooks").run_pre_reload()    M:init()    M:load() @@ -110,7 +113,7 @@ function M:reload()    local plugin_loader = require "lvim.plugin-loader"    plugin_loader.load { plugins, lvim.plugins } -  hooks.run_post_reload() +  require_clean("lvim.utils.hooks").run_post_reload()  end  return M diff --git a/lua/lvim/core/autocmds.lua b/lua/lvim/core/autocmds.lua index e4577e63..712fd323 100644 --- a/lua/lvim/core/autocmds.lua +++ b/lua/lvim/core/autocmds.lua @@ -78,7 +78,7 @@ local get_format_on_save_opts = function()  end  function M.enable_format_on_save(opts) -  local fmd_cmd = string.format(":silent lua vim.lsp.buf.formatting_sync({}, %s)", opts.timeout_ms) +  local fmd_cmd = string.format(":silent lua vim.lsp.buf.formatting_sync({}, %s)", opts.timeout)    M.define_augroups {      format_on_save = { { "BufWritePre", opts.pattern, fmd_cmd } },    } @@ -86,16 +86,12 @@ function M.enable_format_on_save(opts)  end  function M.disable_format_on_save() -  M.remove_augroup "format_on_save" +  M.disable_augroup "format_on_save"    Log:debug "disabled format-on-save"  end  function M.configure_format_on_save()    if lvim.format_on_save then -    if vim.fn.exists "#format_on_save#BufWritePre" == 1 then -      M.remove_augroup "format_on_save" -      Log:debug "reloading format-on-save configuration" -    end      local opts = get_format_on_save_opts()      M.enable_format_on_save(opts)    else @@ -112,24 +108,73 @@ function M.toggle_format_on_save()    end  end -function M.remove_augroup(name) -  if vim.fn.exists("#" .. name) == 1 then -    vim.cmd("au! " .. name) -  end +function M.enable_lsp_document_highlight(client_id) +  M.define_augroups({ +    lsp_document_highlight = { +      { +        "CursorHold", +        "<buffer>", +        string.format("lua require('lvim.lsp.utils').conditional_document_highlight(%d)", client_id), +      }, +      { +        "CursorMoved", +        "<buffer>", +        "lua vim.lsp.buf.clear_references()", +      }, +    }, +  }, true) +end + +function M.disable_lsp_document_highlight() +  M.disable_augroup "lsp_document_highlight" +end + +function M.enable_code_lens_refresh() +  M.define_augroups({ +    lsp_code_lens_refresh = { +      { +        "InsertLeave ", +        "<buffer>", +        "lua vim.lsp.codelens.refresh()", +      }, +      { +        "InsertLeave ", +        "<buffer>", +        "lua vim.lsp.codelens.display()", +      }, +    }, +  }, true)  end -function M.define_augroups(definitions) -- {{{1 -  -- Create autocommand groups based on the passed definitions -  -- -  -- The key will be the name of the group, and each definition -  -- within the group should have: -  --    1. Trigger -  --    2. Pattern -  --    3. Text -  -- just like how they would normally be defined from Vim itself +function M.disable_code_lens_refresh() +  M.disable_augroup "lsp_code_lens_refresh" +end + +--- Disable autocommand groups if it exists +--- This is more reliable than trying to delete the augroup itself +---@param name string the augroup name +function M.disable_augroup(name) +  -- defer the function in case the autocommand is still in-use +  vim.schedule(function() +    if vim.fn.exists("#" .. name) == 1 then +      vim.cmd("augroup " .. name) +      vim.cmd "autocmd!" +      vim.cmd "augroup END" +    end +  end) +end + +--- Create autocommand groups based on the passed definitions +---@param definitions table contains trigger, pattern and text. The key will be used as a group name +---@param buffer boolean indicate if the augroup should be local to the buffer +function M.define_augroups(definitions, buffer)    for group_name, definition in pairs(definitions) do      vim.cmd("augroup " .. group_name) -    vim.cmd "autocmd!" +    if buffer then +      vim.cmd [[autocmd! * <buffer>]] +    else +      vim.cmd [[autocmd!]] +    end      for _, def in pairs(definition) do        local command = table.concat(vim.tbl_flatten { "autocmd", def }, " ") diff --git a/lua/lvim/core/dashboard.lua b/lua/lvim/core/dashboard.lua index 0f62d973..438b46f3 100644 --- a/lua/lvim/core/dashboard.lua +++ b/lua/lvim/core/dashboard.lua @@ -73,7 +73,7 @@ M.setup = function()    vim.g.dashboard_session_directory = lvim.builtin.dashboard.session_directory    local lvim_site = "lunarvim.org" -  local lvim_version = require("lvim.bootstrap"):get_version "short" +  local lvim_version = require("lvim.utils.git"):get_lvim_version "short"    local num_plugins_loaded = #vim.fn.globpath(get_runtime_dir() .. "/site/pack/packer/start", "*", 0, 1)    local footer = { diff --git a/lua/lvim/core/info.lua b/lua/lvim/core/info.lua index df7b7061..7577f296 100644 --- a/lua/lvim/core/info.lua +++ b/lua/lvim/core/info.lua @@ -19,9 +19,8 @@ end  local function make_formatters_info(ft)    local null_formatters = require "lvim.lsp.null-ls.formatters" -  local registered_formatters = null_formatters.list_registered_providers(ft) -  -- print("reg", vim.inspect(registered_formatters)) -  local supported_formatters = null_formatters.list_available(ft) +  local registered_formatters = null_formatters.list_registered(ft) +  local supported_formatters = null_formatters.list_supported(ft)    local section = {      "Formatters info",      fmt( @@ -37,8 +36,7 @@ end  local function make_code_actions_info(ft)    local null_actions = require "lvim.lsp.null-ls.code_actions" -  local registered_actions = null_actions.list_registered_providers(ft) -  local supported_actions = null_actions.list_available(ft) +  local registered_actions = null_actions.list_registered(ft)    local section = {      "Code actions info",      fmt( @@ -46,7 +44,6 @@ local function make_code_actions_info(ft)        table.concat(registered_actions, "  , "),        vim.tbl_count(registered_actions) > 0 and "  " or ""      ), -    fmt("* Supported: %s", str_list(supported_actions)),    }    return section @@ -54,8 +51,8 @@ end  local function make_linters_info(ft)    local null_linters = require "lvim.lsp.null-ls.linters" -  local supported_linters = null_linters.list_available(ft) -  local registered_linters = null_linters.list_registered_providers(ft) +  local supported_linters = null_linters.list_supported(ft) +  local registered_linters = null_linters.list_registered(ft)    local section = {      "Linters info",      fmt( @@ -168,21 +165,20 @@ function M.toggle_popup(ft)    local function set_syntax_hl()      vim.cmd [[highlight LvimInfoIdentifier gui=bold]]      vim.cmd [[highlight link LvimInfoHeader Type]] -    vim.cmd [[let m=matchadd("LvimInfoHeader", "Treesitter info")]] -    vim.cmd [[let m=matchadd("LvimInfoHeader", "Language Server Protocol (LSP) info")]] -    vim.cmd [[let m=matchadd("LvimInfoHeader", "Formatters info")]] -    vim.cmd [[let m=matchadd("LvimInfoHeader", "Linters info")]] -    vim.cmd [[let m=matchadd("LvimInfoHeader", "Code actions info")]] -    vim.cmd('let m=matchadd("LvimInfoIdentifier", " ' .. ft .. '$")') -    vim.cmd 'let m=matchadd("string", "true")' -    vim.cmd 'let m=matchadd("string", "active")' -    vim.cmd 'let m=matchadd("boolean", "inactive")' -    vim.cmd 'let m=matchadd("string", "")' -    vim.cmd 'let m=matchadd("error", "false")' -    -- tbl_set_highlight(registered_providers, "LvimInfoIdentifier") -    tbl_set_highlight(require("lvim.lsp.null-ls.formatters").list_available(ft), "LvimInfoIdentifier") -    tbl_set_highlight(require("lvim.lsp.null-ls.linters").list_available(ft), "LvimInfoIdentifier") -    tbl_set_highlight(require("lvim.lsp.null-ls.code_actions").list_available(ft), "LvimInfoIdentifier") +    vim.fn.matchadd("LvimInfoHeader", "Treesitter info") +    vim.fn.matchadd("LvimInfoHeader", "Language Server Protocol (LSP) info") +    vim.fn.matchadd("LvimInfoHeader", "Formatters info") +    vim.fn.matchadd("LvimInfoHeader", "Linters info") +    vim.fn.matchadd("LvimInfoHeader", "Code actions info") +    vim.fn.matchadd("LvimInfoIdentifier", " " .. ft .. "$") +    vim.fn.matchadd("string", "true") +    vim.fn.matchadd("string", "active") +    vim.fn.matchadd("string", "") +    vim.fn.matchadd("boolean", "inactive") +    vim.fn.matchadd("error", "false") +    tbl_set_highlight(require("lvim.lsp.null-ls.formatters").list_registered(ft), "LvimInfoIdentifier") +    tbl_set_highlight(require("lvim.lsp.null-ls.linters").list_registered(ft), "LvimInfoIdentifier") +    tbl_set_highlight(require("lvim.lsp.null-ls.code_actions").list_registered(ft), "LvimInfoIdentifier")    end    local Popup = require("lvim.interface.popup"):new { diff --git a/lua/lvim/core/log.lua b/lua/lvim/core/log.lua index f51b8af6..be7930ba 100644 --- a/lua/lvim/core/log.lua +++ b/lua/lvim/core/log.lua @@ -9,29 +9,16 @@ Log.levels = {    WARN = 4,    ERROR = 5,  } -  vim.tbl_add_reverse_lookup(Log.levels) +local notify_opts = {} +  function Log:init()    local status_ok, structlog = pcall(require, "structlog")    if not status_ok then      return nil    end -  local notify_handler = require "lvim.core.notify" - -  ---Check if notify is available -  ---@return boolean -  local is_notify_available = function() -    local in_headless = #vim.api.nvim_list_uis() == 0 -    --We can't rely on lvim.builtin.notify.active since this can be used before the config loader -    local has_notify_plugin = pcall(require, "notify") -    if not in_headless and has_notify_plugin then -      return true -    end -    return false -  end -    local log_level = Log.levels[(lvim.log.level):upper() or "WARN"]    local lvim_log = {      lvim = { @@ -64,50 +51,94 @@ function Log:init()      },    } -  if is_notify_available() then -    table.insert( -      lvim_log.lvim.sinks, -      structlog.sinks.NvimNotify(Log.levels.INFO, { -        processors = { -          notify_handler.default_namer, -          notify_handler.params_injecter, -        }, -        formatter = structlog.formatters.Format( -- -          "%s", -          { "msg" }, -          { blacklist_all = true } -        ), -        params_map = { -          icon = "icon", -          keep = "keep", -          on_open = "on_open", -          on_close = "on_close", -          timeout = "timeout", -          title = "title", -        }, -      }) -    ) -  end -    structlog.configure(lvim_log) -    local logger = structlog.get_logger "lvim" +  -- Overwrite `vim.notify` to use the logger    if lvim.log.override_notify then -    logger:log(Log.levels.INFO, "Ignoring request to override vim.notify with structlog due to instabilities") +    vim.notify = function(msg, vim_log_level, opts) +      notify_opts = opts or {} + +      -- vim_log_level can be omitted +      if vim_log_level == nil then +        vim_log_level = Log.levels["INFO"] +      elseif type(vim_log_level) == "string" then +        vim_log_level = Log.levels[(vim_log_level):upper()] or Log.levels["INFO"] +      else +        -- https://github.com/neovim/neovim/blob/685cf398130c61c158401b992a1893c2405cd7d2/runtime/lua/vim/lsp/log.lua#L5 +        vim_log_level = vim_log_level + 1 +      end + +      logger:log(vim_log_level, msg) +    end    end    return logger  end +--- Configure the sink in charge of logging notifications +---@param notif_handle table The implementation used by the sink for displaying the notifications +function Log:configure_notifications(notif_handle) +  local status_ok, structlog = pcall(require, "structlog") +  if not status_ok then +    return +  end + +  local default_namer = function(logger, entry) +    entry["title"] = logger.name +    return entry +  end + +  local notify_opts_injecter = function(_, entry) +    for key, value in pairs(notify_opts) do +      entry[key] = value +    end +    notify_opts = {} +    return entry +  end + +  local sink = structlog.sinks.NvimNotify(Log.levels.INFO, { +    processors = { +      default_namer, +      notify_opts_injecter, +    }, +    formatter = structlog.formatters.Format( -- +      "%s", +      { "msg" }, +      { blacklist_all = true } +    ), +    -- This should probably not be hard-coded +    params_map = { +      icon = "icon", +      keep = "keep", +      on_open = "on_open", +      on_close = "on_close", +      timeout = "timeout", +      title = "title", +    }, +    impl = notif_handle, +  }) + +  table.insert(self.__handle.sinks, sink) +end +  --- Adds a log entry using Plenary.log ----@fparam msg any +---@param msg any  ---@param level string [same as vim.log.log_levels]  function Log:add_entry(level, msg, event) -  if self.__handle then -    self.__handle:log(level, vim.inspect(msg), event) +  local logger = self:get_logger() +  if not logger then      return    end +  logger:log(level, vim.inspect(msg), event) +end + +---Retrieves the handle of the logger object +---@return table|nil logger handle if found +function Log:get_logger() +  if self.__handle then +    return self.__handle +  end    local logger = self:init()    if not logger then @@ -115,7 +146,7 @@ function Log:add_entry(level, msg, event)    end    self.__handle = logger -  self.__handle:log(level, vim.inspect(msg), event) +  return logger  end  ---Retrieves the path of the logfile diff --git a/lua/lvim/core/lualine/components.lua b/lua/lvim/core/lualine/components.lua index 9cf67616..b1387afa 100644 --- a/lua/lvim/core/lualine/components.lua +++ b/lua/lvim/core/lualine/components.lua @@ -104,17 +104,16 @@ return {        -- add formatter        local formatters = require "lvim.lsp.null-ls.formatters" -      local supported_formatters = formatters.list_registered_providers(buf_ft) +      local supported_formatters = formatters.list_registered(buf_ft)        vim.list_extend(buf_client_names, supported_formatters)        -- add linter        local linters = require "lvim.lsp.null-ls.linters" -      local supported_linters = linters.list_registered_providers(buf_ft) +      local supported_linters = linters.list_registered(buf_ft)        vim.list_extend(buf_client_names, supported_linters)        return "[" .. table.concat(buf_client_names, ", ") .. "]"      end, -    -- icon = " ",      color = { gui = "bold" },      cond = conditions.hide_in_width,    }, diff --git a/lua/lvim/core/notify.lua b/lua/lvim/core/notify.lua index 5339357b..cb62778f 100644 --- a/lua/lvim/core/notify.lua +++ b/lua/lvim/core/notify.lua @@ -1,45 +1,59 @@  local M = {} -function M.config() -  local pallete = require "onedarker.palette" - -  lvim.builtin.notify = { -    active = false, -    on_config_done = nil, -    -- TODO: update after https://github.com/rcarriga/nvim-notify/pull/24 -    opts = { -      ---@usage Animation style one of { "fade", "slide", "fade_in_slide_out", "static" } -      stages = "slide", - -      ---@usage timeout for notifications in ms, default 5000 -      timeout = 5000, - -      ---@usage highlight behind the window for stages that change opacity -      background_colour = pallete.fg, - -      ---@usage Icons for the different levels -      icons = { -        ERROR = "", -        WARN = "", -        INFO = "", -        DEBUG = "", -        TRACE = "✎", -      }, +local Log = require "lvim.core.log" + +local defaults = { +  active = false, +  on_config_done = nil, +  opts = { +    ---@usage Animation style one of { "fade", "slide", "fade_in_slide_out", "static" } +    stages = "slide", + +    ---@usage Function called when a new window is opened, use for changing win settings/config +    on_open = nil, + +    ---@usage Function called when a window is closed +    on_close = nil, + +    ---@usage timeout for notifications in ms, default 5000 +    timeout = 5000, + +    -- Render function for notifications. See notify-render() +    render = "default", + +    ---@usage highlight behind the window for stages that change opacity +    background_colour = "Normal", + +    ---@usage minimum width for notification windows +    minimum_width = 50, + +    ---@usage Icons for the different levels +    icons = { +      ERROR = "", +      WARN = "", +      INFO = "", +      DEBUG = "", +      TRACE = "✎",      }, -  } +  }, +} + +function M.config() +  lvim.builtin.notify = vim.tbl_deep_extend("force", defaults, lvim.builtin.notify or {})  end -M.params_injecter = function(_, entry) -  -- FIXME: this is currently getting ignored or is not passed correctly -  for key, value in pairs(lvim.builtin.notify.opts) do -    entry[key] = value +function M.setup() +  if #vim.api.nvim_list_uis() == 0 then +    -- no need to configure notifications in headless +    return    end -  return entry -end -M.default_namer = function(logger, entry) -  entry["title"] = logger.name -  return entry +  local opts = lvim.builtin.notify and lvim.builtin.notify.opts or defaults +  local notify = require "notify" + +  notify.setup(opts) +  vim.notify = notify +  Log:configure_notifications(notify)  end  return M diff --git a/lua/lvim/core/telescope/custom-finders.lua b/lua/lvim/core/telescope/custom-finders.lua index 5ce1485c..18307fbd 100644 --- a/lua/lvim/core/telescope/custom-finders.lua +++ b/lua/lvim/core/telescope/custom-finders.lua @@ -82,4 +82,14 @@ function M.view_lunarvim_changelog()    }):find()  end +-- Smartly opens either git_files or find_files, depending on whether the working directory is +-- contained in a Git repo. +function M.find_project_files() +  local ok = pcall(builtin.git_files) + +  if not ok then +    builtin.find_files() +  end +end +  return M diff --git a/lua/lvim/core/treesitter.lua b/lua/lvim/core/treesitter.lua index 8dbbcacb..d8b0c136 100644 --- a/lua/lvim/core/treesitter.lua +++ b/lua/lvim/core/treesitter.lua @@ -74,16 +74,20 @@ M.config = function()  end  M.setup = function() +  -- avoid running in headless mode since it's harder to detect failures +  if #vim.api.nvim_list_uis() == 0 then +    Log:debug "headless mode detected, skipping running setup for treesitter" +    return +  end +    local status_ok, treesitter_configs = pcall(require, "nvim-treesitter.configs")    if not status_ok then -    Log:get_default().error "Failed to load nvim-treesitter.configs" +    Log:error "Failed to load nvim-treesitter.configs"      return    end    local opts = vim.deepcopy(lvim.builtin.treesitter) -  -- avoid running any installers in headless mode since it's harder to detect failures -  opts.ensure_installed = #vim.api.nvim_list_uis() == 0 and {} or opts.ensure_installed    treesitter_configs.setup(opts)    if lvim.builtin.treesitter.on_config_done then diff --git a/lua/lvim/core/which-key.lua b/lua/lvim/core/which-key.lua index 88af028f..8691a9a6 100644 --- a/lua/lvim/core/which-key.lua +++ b/lua/lvim/core/which-key.lua @@ -61,14 +61,14 @@ M.config = function()      -- NOTE: Prefer using : over <cmd> as the latter avoids going back in normal-mode.      -- see https://neovim.io/doc/user/map.html#:map-cmd      vmappings = { -      ["/"] = { "<ESC><CMD>lua require('Comment.api').gc(vim.fn.visualmode())<CR>", "Comment" }, +      ["/"] = { "<ESC><CMD>lua require('Comment.api').toggle_linewise_op(vim.fn.visualmode())<CR>", "Comment" },      },      mappings = {        ["w"] = { "<cmd>w!<CR>", "Save" },        ["q"] = { "<cmd>q!<CR>", "Quit" }, -      ["/"] = { "<cmd>lua require('Comment').toggle()<CR>", "Comment" }, +      ["/"] = { "<cmd>lua require('Comment.api').toggle_current_linewise()<CR>", "Comment" },        ["c"] = { "<cmd>BufferClose!<CR>", "Close Buffer" }, -      ["f"] = { "<cmd>Telescope find_files<CR>", "Find File" }, +      ["f"] = { require("lvim.core.telescope.custom-finders").find_project_files, "Find File" },        ["h"] = { "<cmd>nohlsearch<CR>", "No Highlight" },        b = {          name = "Buffers", @@ -140,23 +140,17 @@ M.config = function()        l = {          name = "LSP",          a = { "<cmd>lua require('lvim.core.telescope').code_actions()<cr>", "Code Action" }, -        d = { -          "<cmd>Telescope lsp_document_diagnostics<cr>", -          "Document Diagnostics", -        }, -        w = { -          "<cmd>Telescope lsp_workspace_diagnostics<cr>", -          "Workspace Diagnostics", -        }, +        d = { "<cmd>Telescope diagnostics bufnr=0 theme=get_ivy<cr>", "Buffer Diagnostics" }, +        w = { "<cmd>Telescope diagnostics<cr>", "Diagnostics" },          f = { "<cmd>lua vim.lsp.buf.formatting()<cr>", "Format" },          i = { "<cmd>LspInfo<cr>", "Info" },          I = { "<cmd>LspInstallInfo<cr>", "Installer Info" },          j = { -          "<cmd>lua vim.lsp.diagnostic.goto_next({popup_opts = {border = lvim.lsp.popup_border}})<cr>", +          "<cmd>lua vim.diagnostic.goto_next()<cr>",            "Next Diagnostic",          },          k = { -          "<cmd>lua vim.lsp.diagnostic.goto_prev({popup_opts = {border = lvim.lsp.popup_border}})<cr>", +          "<cmd>lua vim.diagnostic.goto_prev()<cr>",            "Prev Diagnostic",          },          l = { "<cmd>lua vim.lsp.codelens.run()<cr>", "CodeLens Action" }, @@ -166,7 +160,7 @@ M.config = function()            t = { "<cmd>lua require('lvim.lsp.peek').Peek('typeDefinition')<cr>", "Type Definition" },            i = { "<cmd>lua require('lvim.lsp.peek').Peek('implementation')<cr>", "Implementation" },          }, -        q = { "<cmd>lua vim.lsp.diagnostic.set_loclist()<cr>", "Quickfix" }, +        q = { "<cmd>lua vim.diagnostic.setloclist()<cr>", "Quickfix" },          r = { "<cmd>lua vim.lsp.buf.rename()<cr>", "Rename" },          s = { "<cmd>Telescope lsp_document_symbols<cr>", "Document Symbols" },          S = { diff --git a/lua/lvim/lsp/config.lua b/lua/lvim/lsp/config.lua index 5cfe5b1f..8c7a0dd9 100644 --- a/lua/lvim/lsp/config.lua +++ b/lua/lvim/lsp/config.lua @@ -32,7 +32,11 @@ return {    },    document_highlight = true,    code_lens_refresh = true, -  popup_border = "single", +  float = { +    focusable = false, +    style = "minimal", +    border = "rounded", +  },    on_attach_callback = nil,    on_init_callback = nil,    automatic_servers_installation = true, @@ -61,13 +65,14 @@ return {      "angularls",      "ansiblels",      "ccls", -    "cssmodules_ls",      "csharp_ls", +    "cssmodules_ls",      "denols",      "ember",      "emmet_ls",      "eslint",      "eslintls", +    "grammarly",      "graphql",      "jedi_language_server",      "ltex", @@ -75,15 +80,17 @@ return {      "pylsp",      "quick_lint_js",      "rome", -    "sorbet", -    "sqlls", -    "sqls",      "solang", +    "solidity_ls", +    "sorbet",      "sourcekit",      "spectral", +    "sqlls", +    "sqls",      "stylelint_lsp",      "tailwindcss",      "tflint",      "volar", +    "zk",    },  } diff --git a/lua/lvim/lsp/handlers.lua b/lua/lvim/lsp/handlers.lua index 45f73e91..5da0b21e 100644 --- a/lua/lvim/lsp/handlers.lua +++ b/lua/lvim/lsp/handlers.lua @@ -11,130 +11,15 @@ function M.setup()      severity_sort = lvim.lsp.diagnostics.severity_sort,      float = lvim.lsp.diagnostics.float,    } -  if vim.fn.has "nvim-0.6" == 1 then -    vim.diagnostic.config(config) -  else -    vim.lsp.handlers["textDocument/publishDiagnostics"] = function(_, _, params, client_id, _) -      local uri = params.uri -      local bufnr = vim.uri_to_bufnr(uri) -      if not bufnr then -        return -      end - -      local diagnostics = params.diagnostics -      vim.lsp.diagnostic.save(diagnostics, bufnr, client_id) -      if not vim.api.nvim_buf_is_loaded(bufnr) then -        return -      end -      vim.lsp.diagnostic.display(diagnostics, bufnr, client_id, config) -    end - -    vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { -      border = lvim.lsp.popup_border, -    }) - -    vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { -      border = lvim.lsp.popup_border, -    }) -  end +  vim.diagnostic.config(config) +  vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, lvim.lsp.float) +  vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, lvim.lsp.float)  end  function M.show_line_diagnostics() -  if vim.fn.has "nvim-0.6" == 1 then -    return vim.diagnostic.open_float(0, { scope = "line" }) -  end - -  local function split_by_chunk(text, chunkSize) -    local s = {} -    for i = 1, #text, chunkSize do -      s[#s + 1] = text:sub(i, i + chunkSize - 1) -    end -    return s -  end -  local diagnostics = vim.lsp.diagnostic.get_line_diagnostics() -  local severity_highlight = { -    "LspDiagnosticsFloatingError", -    "LspDiagnosticsFloatingWarning", -    "LspDiagnosticsFloatingInformation", -    "LspDiagnosticsFloatingHint", -  } -  local ok, vim_diag = pcall(require, "vim.diagnostic") -  if ok then -    local buf_id = vim.api.nvim_win_get_buf(0) -    local win_id = vim.api.nvim_get_current_win() -    local cursor_position = vim.api.nvim_win_get_cursor(win_id) -    severity_highlight = { -      "DiagnosticFloatingError", -      "DiagnosticFloatingWarn", -      "DiagnosticFloatingInfo", -      "DiagnosticFloatingHint", -    } -    diagnostics = vim_diag.get(buf_id, { lnum = cursor_position[1] - 1 }) -  end -  local lines = {} -  local max_width = vim.fn.winwidth(0) - 5 -  local height = #diagnostics -  local width = 0 -  local opts = {} -  local close_events = { "CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre" } -  if height == 0 then -    return -  end -  local bufnr = vim.api.nvim_create_buf(false, true) -  local diag_message -  table.sort(diagnostics, function(a, b) -    return a.severity < b.severity -  end) - -  local hash = {} -  local diagnostics_no_dupes = {} -  for _, v in ipairs(diagnostics) do -    if not hash[v["message"]] then -      diagnostics_no_dupes[#diagnostics_no_dupes + 1] = v -- you could print here instead of saving to result table if you wanted -      hash[v["message"]] = true -    end -  end -  -- print(vim.inspect(diagnostics_no_dupes)) - -  for i, diagnostic in ipairs(diagnostics_no_dupes) do -    local source = diagnostic.source -    diag_message = diagnostic.message:gsub("[\n\r]", " ") -    if source then -      if string.find(source, "/") then -        source = string.sub(diagnostic.source, string.find(diagnostic.source, "([%w-_]+)$")) -      end -      diag_message = string.format("%d. %s: %s", i, source, diag_message) -    else -      diag_message = string.format("%d. %s", i, diag_message) -    end -    if diagnostic.code then -      diag_message = string.format("%s [%s]", diag_message, diagnostic.code) -    end -    local msgs = split_by_chunk(diag_message, max_width) -    for _, diag in ipairs(msgs) do -      table.insert(lines, { message = diag, severity = diagnostic.severity }) -      width = math.max(diag:len(), width) -    end -  end -  height = #lines -  opts = vim.lsp.util.make_floating_popup_options(width, height, opts) -  opts["style"] = "minimal" -  opts["border"] = "rounded" -  opts["focusable"] = true - -  vim.api.nvim_buf_set_option(bufnr, "bufhidden", "wipe") -  local winnr = vim.api.nvim_open_win(bufnr, false, opts) -  vim.api.nvim_win_set_option(winnr, "winblend", 0) -  vim.api.nvim_buf_set_var(bufnr, "lsp_floating_window", winnr) -  for i, diag in ipairs(lines) do -    vim.api.nvim_buf_set_lines(bufnr, i - 1, i - 1, 0, { diag.message }) -    vim.api.nvim_buf_add_highlight(bufnr, -1, severity_highlight[diag.severity], i - 1, 0, diag.message:len()) -  end - -  vim.api.nvim_command( -    "autocmd QuitPre <buffer> ++nested ++once lua pcall(vim.api.nvim_win_close, " .. winnr .. ", true)" -  ) -  vim.lsp.util.close_preview_autocmd(close_events, winnr) +  local config = lvim.lsp.diagnostics.float +  config.scope = "line" +  return vim.diagnostic.open_float(0, config)  end  return M diff --git a/lua/lvim/lsp/init.lua b/lua/lvim/lsp/init.lua index 68a64d6c..0be13484 100644 --- a/lua/lvim/lsp/init.lua +++ b/lua/lvim/lsp/init.lua @@ -1,24 +1,13 @@  local M = {}  local Log = require "lvim.core.log"  local utils = require "lvim.utils" +local autocmds = require "lvim.core.autocmds"  local function lsp_highlight_document(client)    if lvim.lsp.document_highlight == false then      return -- we don't need further    end -  -- Set autocommands conditional on server_capabilities -  if client.resolved_capabilities.document_highlight then -    vim.api.nvim_exec( -      [[ -      augroup lsp_document_highlight -        autocmd! * <buffer> -        autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight() -        autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() -      augroup END -    ]], -      false -    ) -  end +  autocmds.enable_lsp_document_highlight(client.id)  end  local function lsp_code_lens_refresh(client) @@ -27,16 +16,7 @@ local function lsp_code_lens_refresh(client)    end    if client.resolved_capabilities.code_lens then -    vim.api.nvim_exec( -      [[ -      augroup lsp_code_lens_refresh -        autocmd! * <buffer> -        autocmd InsertLeave <buffer> lua vim.lsp.codelens.refresh() -        autocmd InsertLeave <buffer> lua vim.lsp.codelens.display() -      augroup END -    ]], -      false -    ) +    autocmds.enable_code_lens_refresh()    end  end @@ -101,6 +81,15 @@ local function select_default_formater(client)    end  end +function M.common_on_exit(_, _) +  if lvim.lsp.document_highlight then +    autocmds.disable_lsp_document_highlight() +  end +  if lvim.lsp.code_lens_refresh then +    autocmds.disable_code_lens_refresh() +  end +end +  function M.common_on_init(client, bufnr)    if lvim.lsp.on_init_callback then      lvim.lsp.on_init_callback(client, bufnr) @@ -132,17 +121,11 @@ function M.get_common_opts()    return {      on_attach = M.common_on_attach,      on_init = M.common_on_init, +    on_exit = M.common_on_exit,      capabilities = M.common_capabilities(),    }  end -local LSP_DEPRECATED_SIGN_MAP = { -  ["DiagnosticSignError"] = "LspDiagnosticsSignError", -  ["DiagnosticSignWarn"] = "LspDiagnosticsSignWarning", -  ["DiagnosticSignHint"] = "LspDiagnosticsSignHint", -  ["DiagnosticSignInfo"] = "LspDiagnosticsSignInformation", -} -  function M.setup()    Log:debug "Setting up LSP support" @@ -151,13 +134,7 @@ function M.setup()      return    end -  local is_neovim_5 = vim.fn.has "nvim-0.6" ~= 1 -    for _, sign in ipairs(lvim.lsp.diagnostics.signs.values) do -    local lsp_sign_name = LSP_DEPRECATED_SIGN_MAP[sign.name] -    if is_neovim_5 and lsp_sign_name then -      vim.fn.sign_define(lsp_sign_name, { texthl = lsp_sign_name, text = sign.text, numhl = lsp_sign_name }) -    end      vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = sign.name })    end @@ -171,7 +148,7 @@ function M.setup()    require("lvim.lsp.null-ls").setup() -  require("lvim.core.autocmds").configure_format_on_save() +  autocmds.configure_format_on_save()  end  return M diff --git a/lua/lvim/lsp/manager.lua b/lua/lvim/lsp/manager.lua index c95b9f69..6c748020 100644 --- a/lua/lvim/lsp/manager.lua +++ b/lua/lvim/lsp/manager.lua @@ -24,6 +24,7 @@ local function resolve_config(name, user_config)    local config = {      on_attach = require("lvim.lsp").common_on_attach,      on_init = require("lvim.lsp").common_on_init, +    on_exit = require("lvim.lsp").common_on_exit,      capabilities = require("lvim.lsp").common_capabilities(),    } diff --git a/lua/lvim/lsp/null-ls/code_actions.lua b/lua/lvim/lsp/null-ls/code_actions.lua index ff59fabf..bf6492b5 100644 --- a/lua/lvim/lsp/null-ls/code_actions.lua +++ b/lua/lvim/lsp/null-ls/code_actions.lua @@ -14,20 +14,11 @@ local is_registered = function(name)    return require("null-ls.sources").is_registered(query)  end -function M.list_registered_providers(filetype) +function M.list_registered(filetype)    local registered_providers = services.list_registered_providers_names(filetype)    return registered_providers[METHOD] or {}  end -function M.list_available(filetype) -  local availables = require("null-ls.sources").get_available(filetype, METHOD) -  local actors = vim.tbl_map(function(src) -    return src.name -  end, availables) -  table.sort(actors) -  return actors -end -  function M.list_configured(actions_configs)    local actors, errors = {}, {} diff --git a/lua/lvim/lsp/null-ls/formatters.lua b/lua/lvim/lsp/null-ls/formatters.lua index b2e191c5..0613f16f 100644 --- a/lua/lvim/lsp/null-ls/formatters.lua +++ b/lua/lvim/lsp/null-ls/formatters.lua @@ -12,26 +12,18 @@ local is_registered = function(name)    return require("null-ls.sources").is_registered(query)  end -function M.list_registered_providers(filetype) +function M.list_registered(filetype)    local null_ls_methods = require "null-ls.methods"    local formatter_method = null_ls_methods.internal["FORMATTING"]    local registered_providers = services.list_registered_providers_names(filetype)    return registered_providers[formatter_method] or {}  end -function M.list_available(filetype) -  local formatters = {} -  local tbl = require "lvim.utils.table" -  for _, provider in pairs(null_ls.builtins.formatting) do -    if tbl.contains(provider.filetypes or {}, function(ft) -      return ft == "*" or ft == filetype -    end) then -      table.insert(formatters, provider.name) -    end -  end - -  table.sort(formatters) -  return formatters +function M.list_supported(filetype) +  local s = require "null-ls.sources" +  local supported_formatters = s.get_supported(filetype, "formatting") +  table.sort(supported_formatters) +  return supported_formatters  end  function M.list_configured(formatter_configs) diff --git a/lua/lvim/lsp/null-ls/init.lua b/lua/lvim/lsp/null-ls/init.lua index f5e820e8..68e20c98 100644 --- a/lua/lvim/lsp/null-ls/init.lua +++ b/lua/lvim/lsp/null-ls/init.lua @@ -9,14 +9,8 @@ function M:setup()      return    end -  null_ls.config(lvim.lsp.null_ls.config)    local default_opts = require("lvim.lsp").get_common_opts() - -  if vim.tbl_isempty(lvim.lsp.null_ls.setup or {}) then -    lvim.lsp.null_ls.setup = default_opts -  end - -  require("lspconfig")["null-ls"].setup(lvim.lsp.null_ls.setup) +  null_ls.setup(vim.tbl_deep_extend("force", default_opts, lvim.lsp.null_ls.setup))  end  return M diff --git a/lua/lvim/lsp/null-ls/linters.lua b/lua/lvim/lsp/null-ls/linters.lua index 6a793d26..67e530a9 100644 --- a/lua/lvim/lsp/null-ls/linters.lua +++ b/lua/lvim/lsp/null-ls/linters.lua @@ -12,26 +12,18 @@ local is_registered = function(name)    return require("null-ls.sources").is_registered(query)  end -function M.list_registered_providers(filetype) +function M.list_registered(filetype)    local null_ls_methods = require "null-ls.methods"    local linter_method = null_ls_methods.internal["DIAGNOSTICS"]    local registered_providers = services.list_registered_providers_names(filetype)    return registered_providers[linter_method] or {}  end -function M.list_available(filetype) -  local linters = {} -  local tbl = require "lvim.utils.table" -  for _, provider in pairs(null_ls.builtins.diagnostics) do -    if tbl.contains(provider.filetypes or {}, function(ft) -      return ft == "*" or ft == filetype -    end) then -      table.insert(linters, provider.name) -    end -  end - -  table.sort(linters) -  return linters +function M.list_supported(filetype) +  local s = require "null-ls.sources" +  local supported_linters = s.get_supported(filetype, "diagnostics") +  table.sort(supported_linters) +  return supported_linters  end  function M.list_configured(linter_configs) diff --git a/lua/lvim/lsp/peek.lua b/lua/lvim/lsp/peek.lua index 08345aff..f006f934 100644 --- a/lua/lvim/lsp/peek.lua +++ b/lua/lvim/lsp/peek.lua @@ -47,9 +47,8 @@ local function create_floating_file(location, opts)    -- Set some autocmds to close the window    vim.api.nvim_command( -    "autocmd QuitPre <buffer> ++nested ++once lua pcall(vim.api.nvim_win_close, " .. winnr .. ", true)" +    string.format("autocmd %s <buffer> ++once lua pcall(vim.api.nvim_win_close, %d, true)", unpack(close_events), winnr)    ) -  vim.lsp.util.close_preview_autocmd(close_events, winnr)    return bufnr, winnr  end @@ -73,10 +72,6 @@ local function preview_location_callback(result)    end  end -local function preview_location_callback_old_signature(_, _, result) -  return preview_location_callback(result) -end -  local function preview_location_callback_new_signature(_, result)    return preview_location_callback(result)  end @@ -136,10 +131,7 @@ function M.Peek(what)    else      -- Make a new request and then create the new window in the callback      local params = vim.lsp.util.make_position_params() -    local preview_callback = preview_location_callback_old_signature -    if vim.fn.has "nvim-0.5.1" > 0 then -      preview_callback = preview_location_callback_new_signature -    end +    local preview_callback = preview_location_callback_new_signature      local success, _ = pcall(vim.lsp.buf_request, 0, "textDocument/" .. what, params, preview_callback)      if not success then        print( diff --git a/lua/lvim/lsp/providers/sumneko_lua.lua b/lua/lvim/lsp/providers/sumneko_lua.lua index 6585c8c7..7c0030c1 100644 --- a/lua/lvim/lsp/providers/sumneko_lua.lua +++ b/lua/lvim/lsp/providers/sumneko_lua.lua @@ -7,8 +7,6 @@ local opts = {        workspace = {          library = {            [require("lvim.utils").join_paths(get_runtime_dir(), "lvim", "lua")] = true, -          [vim.fn.expand "$VIMRUNTIME/lua"] = true, -          [vim.fn.expand "$VIMRUNTIME/lua/vim/lsp"] = true,          },          maxPreload = 100000,          preloadFileSize = 10000, @@ -16,4 +14,21 @@ local opts = {      },    },  } -return opts + +local lua_dev_loaded, lua_dev = pcall(require, "lua-dev") +if not lua_dev_loaded then +  return opts +end + +local dev_opts = { +  library = { +    vimruntime = true, -- runtime path +    types = true, -- full signature, docs and completion of vim.api, vim.treesitter, vim.lsp and others +    -- plugins = true, -- installed opt or start plugins in packpath +    -- you can also specify the list of plugins to make available as a workspace library +    plugins = { "plenary.nvim" }, +  }, +  lspconfig = opts, +} + +return lua_dev.setup(dev_opts) diff --git a/lua/lvim/lsp/utils.lua b/lua/lvim/lsp/utils.lua index 6d1ed09c..47b1c8ba 100644 --- a/lua/lvim/lsp/utils.lua +++ b/lua/lvim/lsp/utils.lua @@ -76,4 +76,14 @@ function M.get_all_supported_filetypes()    return vim.tbl_keys(lsp_installer_filetypes or {})  end +function M.conditional_document_highlight(id) +  local client_ok, method_supported = pcall(function() +    return vim.lsp.get_client_by_id(id).resolved_capabilities.document_highlight +  end) +  if not client_ok or not method_supported then +    return +  end +  vim.lsp.buf.document_highlight() +end +  return M diff --git a/lua/lvim/plugins.lua b/lua/lvim/plugins.lua index ef53c3d4..0d429ff0 100644 --- a/lua/lvim/plugins.lua +++ b/lua/lvim/plugins.lua @@ -1,38 +1,38 @@  local commit = {    barbar = "6e638309efcad2f308eb9c5eaccf6f62b794bbab", -  cmp_buffer = "a0fe52489ff6e235d62407f8fa72aef80222040a", +  cmp_buffer = "a01cfeca70594f505b2f086501e90fb6c2f2aaaa",    cmp_luasnip = "7bd2612533db6863381193df83f9934b373b21e1",    cmp_nvim_lsp = "134117299ff9e34adde30a735cd8ca9cf8f3db81", -  cmp_nvim_lua = "d276254e7198ab7d00f117e88e223b4bd8c02d21", -  cmp_path = "d83839ae510d18530c6d36b662a9e806d4dceb73", -  comment = "eb0a84a2ea42858a2bb3cdf5fabe54e7c700555d", +  cmp_path = "4d58224e315426e5ac4c5b218ca86cab85f80c79", +  comment = "1840a1c085d9f662de4f3cb36fc577a305628b8d",    dapinstall = "dd09e9dd3a6e29f02ac171515b8a089fb82bb425",    fixcursorhold = "0e4e22d21975da60b0fd2d302285b3b603f9f71e", -  friendly_snippets = "4bd6974bd3fcf036a29810bf0570acea55cecfb6", -  gitsigns = "a451f97117bd1ede582a6b9db61c387c48d880b6", -  lualine = "c4a09735a68c30981c223310848f0649235ec2be", -  luasnip = "21bdf396438b98e12d5cd7c0210804e379babae3", -  nlsp_settings = "5647a930a0883362b609acb6bfe29cce4202f75d", -  null_ls = "fb9e2a64ae8e43c2255025064cfee37dc7d6a752", -  nvim_autopairs = "04cd1779f81e9d50d5a116c5dccd054b275bd191", -  nvim_cmp = "47d7cfc06abd8661e28dc919882a2fcf01c99729", -  nvim_dap = "9b8c27d6dcc21b69834fe9c2d344e49030783390", -  nvim_lsp_installer = "4d4677739f52b4aeab8909548b37cc88479c315e", -  nvim_lspconfig = "c018b1e92e66b3429a2f167d59211846774f1e3b", -  nvim_notify = "ef027e34b618eac42fb0111c1db670ba01793039", -  nvim_tree = "f408781a463c2edc3a49091b1bca5a18f790ee3d", -  nvim_treesitter = "7474cb06c2be750eae92da51ff7791deb3b21397", +  friendly_snippets = "2c96761c3dbeb786875712961fcadb7aa4e16864", +  gitsigns = "c18fc65c77abf95ac2e7783b9e7455a7a2fab26c", +  lua_dev = "03a44ec6a54b0a025a633978e8541584a02e46d9", +  lualine = "a11f6d15d4d8c9ca9105838d3087ac6281bb6acc", +  luasnip = "b5a72f1fbde545be101fcd10b70bcd51ea4367de", +  nlsp_settings = "1b376a0b7dc60238e835dd0467135ba9a1557ec7", +  null_ls = "0327c839c79b1e5087dac7c47dc3c0c2d8ca5d29", +  nvim_autopairs = "a9b6b98de3bacacc0c986d9b0673cae6a87c4a41", +  nvim_cmp = "1b94aacada96d2a33fef2ecf87748b27a2f50630", +  nvim_dap = "a6fa644f9de62c594a8a9cf6f2aaf324b5a6108b", +  nvim_lsp_installer = "09e602e1ee7c14687b35a15c229d93d167698ef2", +  nvim_lspconfig = "4b21740aae18ecec2d527b79d1072b3b01bb5a2a", +  nvim_notify = "15f52efacd169ea26b0f4070451d3ea53f98cd5a", +  nvim_tree = "0a2f6b0b6ba558a88c77a6b262af647760e6eca8", +  nvim_treesitter = "fa2a6b68aaa6df0187b5bbebe6cbadc120d4a65a",    nvim_ts_context_commentstring = "097df33c9ef5bbd3828105e4bee99965b758dc3f", -  nvim_web_devicons = "344331467509802e1af200f08ec3da278be5cbba", +  nvim_web_devicons = "ac71ca88b1136e1ecb2aefef4948130f31aa40d1",    packer = "851c62c5ecd3b5adc91665feda8f977e104162a5", -  plenary = "e6267f79481064eee53950571f53cbaafb08417d", +  plenary = "a672e11c816d4a91ef01253ba1a2567d20e08e55",    popup = "b7404d35d5d3548a82149238289fa71f7f6de4ac",    project = "71d0e23dcfc43cfd6bb2a97dc5a7de1ab47a6538",    structlog = "6f1403a192791ff1fa7ac845a73de9e860f781f1", -  telescope = "80cdb00b221f69348afc4fb4b701f51eb8dd3120", -- see telescope.nvim#1549 +  telescope = "1d1da664eb6505c318d405eea3d633c451edc2d8",    telescope_fzf_native = "b8662b076175e75e6497c59f3e2799b879d7b954",    toggleterm = "265bbff68fbb8b2a5fb011272ec469850254ec9f", -  which_key = "0fd9de78fe09215e1b7c6173ff1b0b90c8ed6ec4", +  which_key = "312c386ee0eafc925c27869d2be9c11ebdb807eb",  }  return { @@ -53,6 +53,10 @@ return {      "rcarriga/nvim-notify",      commit = commit.nvim_notify,      disable = not lvim.builtin.notify.active, +    config = function() +      require("lvim.core.notify").setup() +    end, +    event = "BufRead",    },    { "Tastyep/structlog.nvim", commit = commit.structlog }, @@ -115,8 +119,9 @@ return {      commit = commit.cmp_path,    },    { -    "hrsh7th/cmp-nvim-lua", -    commit = commit.cmp_nvim_lua, +    "folke/lua-dev.nvim", +    module = "lua-dev", +    commit = commit.lua_dev,    },    -- Autopairs diff --git a/lua/lvim/utils.lua b/lua/lvim/utils.lua new file mode 100644 index 00000000..74bac43f --- /dev/null +++ b/lua/lvim/utils.lua @@ -0,0 +1,107 @@ +local M = {} +local uv = vim.loop + +-- recursive Print (structure, limit, separator) +local function r_inspect_settings(structure, limit, separator) +  limit = limit or 100 -- default item limit +  separator = separator or "." -- indent string +  if limit < 1 then +    print "ERROR: Item limit reached." +    return limit - 1 +  end +  if structure == nil then +    io.write("-- O", separator:sub(2), " = nil\n") +    return limit - 1 +  end +  local ts = type(structure) + +  if ts == "table" then +    for k, v in pairs(structure) do +      -- replace non alpha keys with ["key"] +      if tostring(k):match "[^%a_]" then +        k = '["' .. tostring(k) .. '"]' +      end +      limit = r_inspect_settings(v, limit, separator .. "." .. tostring(k)) +      if limit < 0 then +        break +      end +    end +    return limit +  end + +  if ts == "string" then +    -- escape sequences +    structure = string.format("%q", structure) +  end +  separator = separator:gsub("%.%[", "%[") +  if type(structure) == "function" then +    -- don't print functions +    io.write("-- lvim", separator:sub(2), " = function ()\n") +  else +    io.write("lvim", separator:sub(2), " = ", tostring(structure), "\n") +  end +  return limit - 1 +end + +function M.generate_settings() +  -- Opens a file in append mode +  local file = io.open("lv-settings.lua", "w") + +  -- sets the default output file as test.lua +  io.output(file) + +  -- write all `lvim` related settings to `lv-settings.lua` file +  r_inspect_settings(lvim, 10000, ".") + +  -- closes the open file +  io.close(file) +end + +--- Returns a table with the default values that are missing. +--- either paramter can be empty. +--@param config (table) table containing entries that take priority over defaults +--@param default_config (table) table contatining default values if found +function M.apply_defaults(config, default_config) +  config = config or {} +  default_config = default_config or {} +  local new_config = vim.tbl_deep_extend("keep", vim.empty_dict(), config) +  new_config = vim.tbl_deep_extend("keep", new_config, default_config) +  return new_config +end + +--- Checks whether a given path exists and is a file. +--@param path (string) path to check +--@returns (bool) +function M.is_file(path) +  local stat = uv.fs_stat(path) +  return stat and stat.type == "file" or false +end + +--- Checks whether a given path exists and is a directory +--@param path (string) path to check +--@returns (bool) +function M.is_directory(path) +  local stat = uv.fs_stat(path) +  return stat and stat.type == "directory" or false +end + +M.join_paths = _G.join_paths + +---Write data to a file +---@param path string can be full or relative to `cwd` +---@param txt string|table text to be written, uses `vim.inspect` internally for tables +---@param flag string used to determine access mode, common flags: "w" for `overwrite` or "a" for `append` +function M.write_file(path, txt, flag) +  local data = type(txt) == "string" and txt or vim.inspect(txt) +  uv.fs_open(path, flag, 438, function(open_err, fd) +    assert(not open_err, open_err) +    uv.fs_write(fd, data, -1, function(write_err) +      assert(not write_err, write_err) +      uv.fs_close(fd, function(close_err) +        assert(not close_err, close_err) +      end) +    end) +  end) +end + +return M diff --git a/lua/lvim/utils/git.lua b/lua/lvim/utils/git.lua new file mode 100644 index 00000000..73ba7c96 --- /dev/null +++ b/lua/lvim/utils/git.lua @@ -0,0 +1,158 @@ +local M = {} + +local Log = require "lvim.core.log" + +local function git_cmd(opts) +  local plenary_loaded, Job = pcall(require, "plenary.job") +  if not plenary_loaded then +    vim.cmd "packadd plenary.nvim" +  end + +  opts = opts or {} +  opts.cwd = opts.cwd or get_lvim_base_dir() + +  local stderr = {} +  local stdout, ret = Job +    :new({ +      command = "git", +      args = opts.args, +      cwd = opts.cwd, +      on_stderr = function(_, data) +        table.insert(stderr, data) +      end, +    }) +    :sync() + +  if not vim.tbl_isempty(stderr) then +    Log:debug(stderr) +  end + +  if not vim.tbl_isempty(stdout) then +    Log:debug(stdout) +  end + +  return ret, stdout +end + +local function safe_deep_fetch() +  local ret, result = git_cmd { args = { "rev-parse", "--is-shallow-repository" } } +  if ret ~= 0 then +    Log:error "Git fetch failed! Check the log for further information" +    return +  end +  -- git fetch --unshallow will cause an error on a a complete clone +  local fetch_mode = result[1] == "true" and "--unshallow" or "--all" +  ret = git_cmd { args = { "fetch", fetch_mode } } +  if ret ~= 0 then +    Log:error "Git fetch failed! Check the log for further information" +    return +  end +  return true +end + +---pulls the latest changes from github +function M.update_base_lvim() +  Log:info "Checking for updates" + +  local ret = git_cmd { args = { "fetch" } } +  if ret ~= 0 then +    Log:error "Update failed! Check the log for further information" +    return +  end + +  ret = git_cmd { args = { "diff", "--quiet", "@{upstream}" } } +  if ret == 0 then +    Log:info "LunarVim is already up-to-date" +    return +  end + +  ret = git_cmd { args = { "merge", "--ff-only", "--progress" } } +  if ret ~= 0 then +    Log:error "Update failed! Please pull the changes manually instead." +    return +  end +end + +---Switch Lunarvim to the specified development branch +---@param branch string +function M.switch_lvim_branch(branch) +  if not safe_deep_fetch() then +    return +  end +  local ret = git_cmd { args = { "switch", branch } } +  if ret ~= 0 then +    Log:error "Unable to switch branches! Check the log for further information" +    return +  end +end + +---Get the current Lunarvim development branch +---@return string|nil +function M.get_lvim_branch() +  local ret, branch = git_cmd { args = { "branch", "--show-current" } } +  if ret ~= 0 or (not branch or branch[1] == "") then +    Log:error "Unable to retrieve the name of the current branch. Check the log for further information" +    return +  end +  return branch[1] +end + +---Get currently checked-out tag of Lunarvim +---@param type string can be "short" +---@return string|nil +function M.get_lvim_tag(type) +  type = type or "" +  local ret, results = git_cmd { args = { "describe", "--tags" } } +  local lvim_full_ver = results[1] or "" + +  if ret ~= 0 or string.match(lvim_full_ver, "%d") == nil then +    Log:error "Unable to retrieve current tag. Check the log for further information" +    return nil +  end +  if type == "short" then +    return vim.fn.split(lvim_full_ver, "-")[1] +  else +    return string.sub(lvim_full_ver, 1, #lvim_full_ver - 1) +  end +end + +---Get the commit hash of currently checked-out commit of Lunarvim +---@param type string can be "short" +---@return string|nil +function M.get_lvim_version(type) +  type = type or "" +  local branch = M.get_lvim_branch() +  if branch == "master" then +    return M.get_lvim_tag(type) +  end +  local ret, log_results = git_cmd { args = { "log", "--pretty=format:%h", "-1" } } +  local abbrev_version = log_results[1] or "" +  if ret ~= 0 or string.match(abbrev_version, "%d") == nil then +    Log:error "Unable to retrieve current version. Check the log for further information" +    return nil +  end +  if type == "short" then +    return abbrev_version +  end +  return branch .. "-" .. abbrev_version +end + +function M.generate_plugins_sha(output) +  local list = {} +  output = output or "commits.lua" + +  local core_plugins = require "lvim.plugins" +  for _, plugin in pairs(core_plugins) do +    local name = plugin[1]:match "/(%S*)" +    local url = "https://github.com/" .. plugin[1] +    print("checking: " .. name .. ", at: " .. url) +    local retval, latest_sha = git_cmd { args = { "ls-remote", url, "origin", "HEAD" } } +    if retval == 0 then +      -- replace dashes, remove postfixes and use lowercase +      local normalize_name = (name:gsub("-", "_"):gsub("%.%S+", "")):lower() +      list[normalize_name] = latest_sha[1]:gsub("\tHEAD", "") +    end +  end +  require("lvim.utils").write_file(output, "local commit = " .. vim.inspect(list), "w") +end +return M diff --git a/lua/lvim/utils/hooks.lua b/lua/lvim/utils/hooks.lua index 9b02b958..ab7dfacd 100644 --- a/lua/lvim/utils/hooks.lua +++ b/lua/lvim/utils/hooks.lua @@ -21,14 +21,14 @@ function M.run_on_packer_complete()    require("lvim.plugin-loader").recompile()    -- forcefully activate nvim-web-devicons    require("nvim-web-devicons").set_up_highlights() +  if package.loaded["lspconfig"] then +    vim.cmd [[ LspStart ]] +  end    Log:info "Reloaded configuration"  end  function M.run_post_reload()    Log:debug "Starting post-reload hook" -  if package.loaded["lspconfig"] then -    vim.cmd [[ LspRestart ]] -  end    M.reset_cache()    require("lvim.plugin-loader").ensure_installed() @@ -68,7 +68,7 @@ function M.run_post_update()        -- TODO: add a changelog        vim.notify("Update complete", vim.log.levels.INFO)        if package.loaded["lspconfig"] then -        vim.cmd [[ LspRestart ]] +        vim.cmd [[ LspStart ]]        end      end)    end diff --git a/lua/lvim/utils/init.lua b/lua/lvim/utils/init.lua deleted file mode 100644 index cafcf506..00000000 --- a/lua/lvim/utils/init.lua +++ /dev/null @@ -1,211 +0,0 @@ -local utils = {} -local uv = vim.loop - --- recursive Print (structure, limit, separator) -local function r_inspect_settings(structure, limit, separator) -  limit = limit or 100 -- default item limit -  separator = separator or "." -- indent string -  if limit < 1 then -    print "ERROR: Item limit reached." -    return limit - 1 -  end -  if structure == nil then -    io.write("-- O", separator:sub(2), " = nil\n") -    return limit - 1 -  end -  local ts = type(structure) - -  if ts == "table" then -    for k, v in pairs(structure) do -      -- replace non alpha keys with ["key"] -      if tostring(k):match "[^%a_]" then -        k = '["' .. tostring(k) .. '"]' -      end -      limit = r_inspect_settings(v, limit, separator .. "." .. tostring(k)) -      if limit < 0 then -        break -      end -    end -    return limit -  end - -  if ts == "string" then -    -- escape sequences -    structure = string.format("%q", structure) -  end -  separator = separator:gsub("%.%[", "%[") -  if type(structure) == "function" then -    -- don't print functions -    io.write("-- lvim", separator:sub(2), " = function ()\n") -  else -    io.write("lvim", separator:sub(2), " = ", tostring(structure), "\n") -  end -  return limit - 1 -end - -function utils.generate_settings() -  -- Opens a file in append mode -  local file = io.open("lv-settings.lua", "w") - -  -- sets the default output file as test.lua -  io.output(file) - -  -- write all `lvim` related settings to `lv-settings.lua` file -  r_inspect_settings(lvim, 10000, ".") - -  -- closes the open file -  io.close(file) -end - -function utils.unrequire(m) -  package.loaded[m] = nil -  _G[m] = nil -end - -function utils.gsub_args(args) -  if args == nil or type(args) ~= "table" then -    return args -  end -  local buffer_filepath = vim.fn.fnameescape(vim.api.nvim_buf_get_name(0)) -  for i = 1, #args do -    args[i] = string.gsub(args[i], "${FILEPATH}", buffer_filepath) -  end -  return args -end - ---- Returns a table with the default values that are missing. ---- either paramter can be empty. ---@param config (table) table containing entries that take priority over defaults ---@param default_config (table) table contatining default values if found -function utils.apply_defaults(config, default_config) -  config = config or {} -  default_config = default_config or {} -  local new_config = vim.tbl_deep_extend("keep", vim.empty_dict(), config) -  new_config = vim.tbl_deep_extend("keep", new_config, default_config) -  return new_config -end - ---- Checks whether a given path exists and is a file. ---@param path (string) path to check ---@returns (bool) -function utils.is_file(path) -  local stat = uv.fs_stat(path) -  return stat and stat.type == "file" or false -end - ---- Checks whether a given path exists and is a directory ---@param path (string) path to check ---@returns (bool) -function utils.is_directory(path) -  local stat = uv.fs_stat(path) -  return stat and stat.type == "directory" or false -end - -utils.join_paths = _G.join_paths - -function utils.write_file(path, txt, flag) -  uv.fs_open(path, flag, 438, function(open_err, fd) -    assert(not open_err, open_err) -    uv.fs_write(fd, txt, -1, function(write_err) -      assert(not write_err, write_err) -      uv.fs_close(fd, function(close_err) -        assert(not close_err, close_err) -      end) -    end) -  end) -end - -function utils.debounce(ms, fn) -  local timer = vim.loop.new_timer() -  return function(...) -    local argv = { ... } -    timer:start(ms, 0, function() -      timer:stop() -      vim.schedule_wrap(fn)(unpack(argv)) -    end) -  end -end - -function utils.search_file(file, args) -  local Job = require "plenary.job" -  local stderr = {} -  local stdout, ret = Job -    :new({ -      command = "grep", -      args = { args, file }, -      cwd = get_cache_dir(), -      on_stderr = function(_, data) -        table.insert(stderr, data) -      end, -    }) -    :sync() -  return stdout, ret, stderr -end - -function utils.file_contains(file, query) -  local stdout, ret, stderr = utils.search_file(file, query) -  if ret == 0 then -    return true -  end -  if not vim.tbl_isempty(stderr) then -    error(vim.inspect(stderr)) -  end -  if not vim.tbl_isempty(stdout) then -    error(vim.inspect(stdout)) -  end -  return false -end - -function utils.log_contains(query) -  local logfile = require("lvim.core.log"):get_path() -  local stdout, ret, stderr = utils.search_file(logfile, query) -  if ret == 0 then -    return true -  end -  if not vim.tbl_isempty(stderr) then -    error(vim.inspect(stderr)) -  end -  if not vim.tbl_isempty(stdout) then -    error(vim.inspect(stdout)) -  end -  if not vim.tbl_isempty(stderr) then -    error(vim.inspect(stderr)) -  end -  return false -end - -function utils.generate_plugins_sha(output) -  local list = {} -  output = output or "commits.lua" - -  local function git_cmd(args) -    local Job = require "plenary.job" -    local stderr = {} -    local stdout, ret = Job -      :new({ -        command = "git", -        args = args, -        on_stderr = function(_, data) -          table.insert(stderr, data) -        end, -      }) -      :sync() -    return ret, stdout -  end - -  local core_plugins = require "lvim.plugins" -  for _, plugin in pairs(core_plugins) do -    local name = plugin[1]:match "/(%S*)" -    local url = "https://github.com/" .. plugin[1] -    print("checking: " .. name .. ", at: " .. url) -    local retval, latest_sha = git_cmd { "ls-remote", url, "origin", "HEAD" } -    if retval == 0 then -      -- replace dashes, remove postfixes and use lowercase -      local normalize_name = (name:gsub("-", "_"):gsub("%.%S+", "")):lower() -      list[normalize_name] = latest_sha[1]:gsub("\tHEAD", "") -    end -  end -  utils.write_file(output, "local commit = " .. vim.inspect(list), "w") -end - -return utils diff --git a/tests/helpers.lua b/tests/helpers.lua new file mode 100644 index 00000000..ada83267 --- /dev/null +++ b/tests/helpers.lua @@ -0,0 +1,51 @@ +local M = {} + +function M.search_file(file, args) +  local Job = require "plenary.job" +  local stderr = {} +  local stdout, ret = Job +    :new({ +      command = "grep", +      args = { args, file }, +      cwd = get_cache_dir(), +      on_stderr = function(_, data) +        table.insert(stderr, data) +      end, +    }) +    :sync() +  return stdout, ret, stderr +end + +function M.file_contains(file, query) +  local stdout, ret, stderr = M.search_file(file, query) +  if ret == 0 then +    return true +  end +  if not vim.tbl_isempty(stderr) then +    error(vim.inspect(stderr)) +  end +  if not vim.tbl_isempty(stdout) then +    error(vim.inspect(stdout)) +  end +  return false +end + +function M.log_contains(query) +  local logfile = require("lvim.core.log"):get_path() +  local stdout, ret, stderr = M.search_file(logfile, query) +  if ret == 0 then +    return true +  end +  if not vim.tbl_isempty(stderr) then +    error(vim.inspect(stderr)) +  end +  if not vim.tbl_isempty(stdout) then +    error(vim.inspect(stdout)) +  end +  if not vim.tbl_isempty(stderr) then +    error(vim.inspect(stderr)) +  end +  return false +end + +return M diff --git a/tests/minimal_init.lua b/tests/minimal_init.lua index 126f8e6e..0178514b 100644 --- a/tests/minimal_init.lua +++ b/tests/minimal_init.lua @@ -1,5 +1,12 @@  local path_sep = vim.loop.os_uname().version:match "Windows" and "\\" or "/" +local base_dir = os.getenv "LUNARVIM_RUNTIME_DIR" .. path_sep .. "lvim" +local tests_dir = base_dir .. path_sep .. "tests" -vim.opt.rtp:append(os.getenv "LUNARVIM_RUNTIME_DIR" .. path_sep .. "lvim") +vim.opt.rtp = { base_dir, tests_dir, os.getenv "VIMRUNTIME" } + +vim.opt.swapfile = false + +-- load helper functions before any other plugin to avoid name-collisions +pcall(require, "tests.helpers")  require("lvim.bootstrap"):init() diff --git a/tests/minimal_lsp.lua b/tests/minimal_lsp.lua index 9873e5ef..1c496c5a 100644 --- a/tests/minimal_lsp.lua +++ b/tests/minimal_lsp.lua @@ -8,12 +8,7 @@ end  vim.cmd [[set runtimepath=$VIMRUNTIME]] -local temp_dir -if on_windows then -  temp_dir = vim.loop.os_getenv "TEMP" -else -  temp_dir = "/tmp" -end +local temp_dir = vim.loop.os_getenv "TEMP" or "/tmp"  vim.cmd("set packpath=" .. join_paths(temp_dir, "nvim", "site")) @@ -46,9 +41,7 @@ end  _G.load_config = function()    vim.lsp.set_log_level "trace" -  if vim.fn.has "nvim-0.5.1" == 1 then -    require("vim.lsp.log").set_format_func(vim.inspect) -  end +  require("vim.lsp.log").set_format_func(vim.inspect)    local nvim_lsp = require "lspconfig"    local on_attach = function(_, bufnr)      local function buf_set_keymap(...) @@ -73,10 +66,10 @@ _G.load_config = function()      buf_set_keymap("n", "<space>lD", "<cmd>lua vim.lsp.buf.type_definition()<CR>", opts)      buf_set_keymap("n", "<space>lr", "<cmd>lua vim.lsp.buf.rename()<CR>", opts)      buf_set_keymap("n", "gr", "<cmd>lua vim.lsp.buf.references()<CR>", opts) -    buf_set_keymap("n", "gl", "<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>", opts) -    buf_set_keymap("n", "<space>lk", "<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>", opts) -    buf_set_keymap("n", "<space>lj", "<cmd>lua vim.lsp.diagnostic.goto_next()<CR>", opts) -    buf_set_keymap("n", "<space>lq", "<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>", opts) +    buf_set_keymap("n", "gl", "<cmd>lua vim.diagnostic.open_float(0,{scope='line'})<CR>", opts) +    buf_set_keymap("n", "<space>lk", "<cmd>lua vim.diagnostic.goto_prev()<CR>", opts) +    buf_set_keymap("n", "<space>lj", "<cmd>lua vim.diagnostic.goto_next()<CR>", opts) +    buf_set_keymap("n", "<space>lq", "<cmd>lua vim.diagnostic.setloclist()<CR>", opts)      buf_set_keymap("n", "<space>li", "<cmd>LspInfo<CR>", opts)      buf_set_keymap("n", "<space>lI", "<cmd>LspInstallInfo<CR>", opts)    end diff --git a/tests/bootstrap_spec.lua b/tests/specs/bootstrap_spec.lua index c86d22d4..c86d22d4 100644 --- a/tests/bootstrap_spec.lua +++ b/tests/specs/bootstrap_spec.lua diff --git a/tests/config_loader_spec.lua b/tests/specs/config_loader_spec.lua index 1aef0974..1aef0974 100644 --- a/tests/config_loader_spec.lua +++ b/tests/specs/config_loader_spec.lua diff --git a/tests/lsp_spec.lua b/tests/specs/lsp_spec.lua index 17e72577..633aa17c 100644 --- a/tests/lsp_spec.lua +++ b/tests/specs/lsp_spec.lua @@ -1,6 +1,8 @@  local a = require "plenary.async_lib.tests"  local utils = require "lvim.utils" -lvim.lsp.templates_dir = join_paths(get_runtime_dir(), "lvim", "tests", "artifacts") +local helpers = require "tests.helpers" +local temp_dir = vim.loop.os_getenv "TEMP" or "/tmp" +lvim.lsp.templates_dir = join_paths(temp_dir, "lvim", "tests", "artifacts")  a.describe("lsp workflow", function()    local Log = require "lvim.core.log" @@ -40,7 +42,7 @@ a.describe("lsp workflow", function()      -- we need to delay this check until the log gets populated      vim.schedule(function() -      assert.False(utils.log_contains "templates") +      assert.False(helpers.log_contains "templates")      end)    end) @@ -50,7 +52,7 @@ a.describe("lsp workflow", function()      for _, file in ipairs(vim.fn.glob(lvim.lsp.templates_dir .. "/*.lua", 1, 1)) do        for _, server in ipairs(lvim.lsp.override) do -        assert.False(utils.file_contains(file, server)) +        assert.False(helpers.file_contains(file, server))        end      end    end) diff --git a/tests/plugins_load_spec.lua b/tests/specs/plugins_load_spec.lua index 08c96c12..08c96c12 100644 --- a/tests/plugins_load_spec.lua +++ b/tests/specs/plugins_load_spec.lua diff --git a/utils/bin/lvim b/utils/bin/lvim deleted file mode 100644 index e4cd9c75..00000000 --- a/utils/bin/lvim +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -export LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-$HOME/.local/share/lunarvim}" -export LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-$HOME/.config/lvim}" - -exec nvim -u "$LUNARVIM_RUNTIME_DIR/lvim/init.lua" "$@" diff --git a/utils/bin/lvim.template b/utils/bin/lvim.template new file mode 100644 index 00000000..1b18977d --- /dev/null +++ b/utils/bin/lvim.template @@ -0,0 +1,7 @@ +#!/bin/sh + +export LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-RUNTIME_DIR_VAR}" +export LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-CONFIG_DIR_VAR}" +export LUNARVIM_CACHE_DIR="${LUNARVIM_CACHE_DIR:-CACHE_DIR_VAR}" + +exec nvim -u "$LUNARVIM_RUNTIME_DIR/lvim/init.lua" "$@" diff --git a/utils/bin/test_runner.sh b/utils/bin/test_runner.sh index 6fc6858b..5b7f81ac 100644 --- a/utils/bin/test_runner.sh +++ b/utils/bin/test_runner.sh @@ -18,7 +18,7 @@ lvim() {  if [ -n "$1" ]; then    lvim --headless -c "lua require('plenary.busted').run('$1')"  else -  lvim --headless -c "PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal_init.lua' }" +  lvim --headless -c "PlenaryBustedDirectory tests/specs { minimal_init = './tests/minimal_init.lua' }"  fi  rm -rf "$TEST_BASE_DIR" diff --git a/utils/installer/config.example.lua b/utils/installer/config.example.lua index 03906ada..e3d9fa23 100644 --- a/utils/installer/config.example.lua +++ b/utils/installer/config.example.lua @@ -55,6 +55,7 @@ lvim.keys.normal_mode["<C-s>"] = ":w<cr>"  -- TODO: User Config for predefined plugins  -- After changing plugin config exit and reopen LunarVim, Run :PackerInstall :PackerCompile  lvim.builtin.dashboard.active = true +lvim.builtin.notify.active = true  lvim.builtin.terminal.active = true  lvim.builtin.nvimtree.setup.view.side = "left"  lvim.builtin.nvimtree.show_icons.git = 0 @@ -100,9 +101,7 @@ lvim.builtin.treesitter.highlight.enabled = true  --   buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc")  -- end  -- you can overwrite the null_ls setup table (useful for setting the root_dir function) --- lvim.lsp.null_ls.setup = { ---   root_dir = require("lspconfig").util.root_pattern("Makefile", ".git", "node_modules"), --- } +-- lvim.lsp.null_ls.setup.root_dir = require("lspconfig").util.root_pattern("Makefile", ".git", "node_modules")  -- or if you need something more advanced  -- lvim.lsp.null_ls.setup.root_dir = function(fname)  --   if vim.bo.filetype == "javascript" then diff --git a/utils/installer/install.sh b/utils/installer/install.sh index 1dc77513..c30f2efe 100755 --- a/utils/installer/install.sh +++ b/utils/installer/install.sh @@ -171,12 +171,11 @@ function print_missing_dep_msg() {  }  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' +  local verify_version_cmd='if !has("nvim-0.6.0") | 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" +    echo "[ERROR]: LunarVim requires at least Neovim v0.6.0 or higher"      exit 1    fi  } @@ -223,19 +222,29 @@ function __install_nodejs_deps_yarn() {  function __validate_node_installation() {    local pkg_manager="$1"    local manager_home -  manager_home="$($pkg_manager config get prefix 2>/dev/null)" + +  if ! command -v "$pkg_manager" &>/dev/null; then +    return 1 +  fi + +  if [ "$pkg_manager" == "npm" ]; then +    manager_home="$(npm config get prefix 2>/dev/null)" +  else +    manager_home="$(yarn global bin 2>/dev/null)" +  fi    if [ ! -d "$manager_home" ] || [ ! -w "$manager_home" ]; then -    echo "[ERROR] Unable to install without administrative privilages. Please set you NPM_HOME correctly and try again." -    exit 1 +    echo "[ERROR] Unable to install using [$pkg_manager] without administrative privileges." +    return 1    fi + +  return 0  }  function install_nodejs_deps() {    local -a pkg_managers=("yarn" "npm")    for pkg_manager in "${pkg_managers[@]}"; do -    if command -v "$pkg_manager" &>/dev/null; then -      __validate_node_installation "$pkg_manager" +    if __validate_node_installation "$pkg_manager"; then        eval "__install_nodejs_deps_$pkg_manager"        return      fi @@ -343,18 +352,7 @@ function link_local_lvim() {  }  function setup_shim() { -  if [ ! -d "$INSTALL_PREFIX/bin" ]; then -    mkdir -p "$INSTALL_PREFIX/bin" -  fi -  cat >"$INSTALL_PREFIX/bin/lvim" <<EOF -#!/bin/sh - -export LUNARVIM_CONFIG_DIR="\${LUNARVIM_CONFIG_DIR:-$LUNARVIM_CONFIG_DIR}" -export LUNARVIM_RUNTIME_DIR="\${LUNARVIM_RUNTIME_DIR:-$LUNARVIM_RUNTIME_DIR}" - -exec nvim -u "\$LUNARVIM_RUNTIME_DIR/lvim/init.lua" "\$@" -EOF -  chmod +x "$INSTALL_PREFIX/bin/lvim" +  make -C "$LUNARVIM_BASE_DIR" install-bin  }  function remove_old_cache_files() { diff --git a/utils/installer/install_bin.sh b/utils/installer/install_bin.sh index 2438d5d1..4c649b44 100755 --- a/utils/installer/install_bin.sh +++ b/utils/installer/install_bin.sh @@ -1,33 +1,37 @@  #!/usr/bin/env bash  set -eo pipefail -declare -r INSTALL_PREFIX="${INSTALL_PREFIX:-"$HOME/.local"}" +INSTALL_PREFIX="${INSTALL_PREFIX:-"$HOME/.local"}" -declare -r XDG_DATA_HOME="${XDG_DATA_HOME:-"$HOME/.local/share"}" -declare -r XDG_CACHE_HOME="${XDG_CACHE_HOME:-"$HOME/.cache"}" -declare -r XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-"$HOME/.config"}" +XDG_DATA_HOME="${XDG_DATA_HOME:-"$HOME/.local/share"}" +XDG_CACHE_HOME="${XDG_CACHE_HOME:-"$HOME/.cache"}" +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"}" +LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-"$XDG_DATA_HOME/lunarvim"}" +LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-"$XDG_CONFIG_HOME/lvim"}" +LUNARVIM_CACHE_DIR="${LUNARVIM_CACHE_DIR:-"$XDG_CACHE_HOME/nvim"}" -# TODO: Use a dedicated cache directory #1256 -declare -r LUNARVIM_CACHE_DIR="$XDG_CACHE_HOME/nvim" +LUNARVIM_BASE_DIR="${LUNARVIM_BASE_DIR:-"$LUNARVIM_RUNTIME_DIR/lvim"}"  function setup_shim() { -  if [ ! -d "$INSTALL_PREFIX/bin" ]; then -    mkdir -p "$INSTALL_PREFIX/bin" -  fi -  cat >"$INSTALL_PREFIX/bin/lvim" <<EOF -#!/bin/sh - -export LUNARVIM_CONFIG_DIR="\${LUNARVIM_CONFIG_DIR:-$LUNARVIM_CONFIG_DIR}" -export LUNARVIM_RUNTIME_DIR="\${LUNARVIM_RUNTIME_DIR:-$LUNARVIM_RUNTIME_DIR}" -export LUNARVIM_CACHE_DIR="\${LUNARVIM_CACHE_DIR:-$LUNARVIM_CACHE_DIR}" - -exec nvim -u "\$LUNARVIM_RUNTIME_DIR/lvim/init.lua" "\$@" -EOF -  chmod +x "$INSTALL_PREFIX/bin/lvim" +  local src="$LUNARVIM_BASE_DIR/utils/bin/lvim.template" +  local dst="$INSTALL_PREFIX/bin/lvim" + +  [ ! -d "$INSTALL_PREFIX/bin" ] && mkdir -p "$INSTALL_PREFIX/bin" + +  # remove outdated installation so that `cp` doesn't complain +  rm -f "$dst" + +  cp "$src" "$dst" + +  sed -e s"@RUNTIME_DIR_VAR@\"${LUNARVIM_RUNTIME_DIR}\"@"g \ +    -e s"@CONFIG_DIR_VAR@\"${LUNARVIM_CONFIG_DIR}\"@"g \ +    -e s"@CACHE_DIR_VAR@\"${LUNARVIM_CACHE_DIR}\"@"g "$src" \ +    | tee "$dst" >/dev/null + +  chmod u+x "$dst"  }  setup_shim "$@" +  echo "You can start LunarVim by running: $INSTALL_PREFIX/bin/lvim" | 
