فهرست منبع

Merge branch 'rolling'

kylo252 3 سال پیش
والد
کامیت
e5aa8be8ce
47فایلهای تغییر یافته به همراه858 افزوده شده و 866 حذف شده
  1. 3 3
      .github/ISSUE_TEMPLATE/config.yml
  2. 7 16
      .github/ISSUE_TEMPLATE/feature-form.yaml
  3. 21 19
      .github/ISSUE_TEMPLATE/general-issue-form.yaml
  4. 50 43
      .github/ISSUE_TEMPLATE/lsp-issue-form.yaml
  5. 1 2
      .luacheckrc
  6. 9 5
      Makefile
  7. 3 1
      README.md
  8. 21 100
      lua/lvim/bootstrap.lua
  9. 7 4
      lua/lvim/config/init.lua
  10. 65 20
      lua/lvim/core/autocmds.lua
  11. 1 1
      lua/lvim/core/dashboard.lua
  12. 19 23
      lua/lvim/core/info.lua
  13. 77 46
      lua/lvim/core/log.lua
  14. 2 3
      lua/lvim/core/lualine/components.lua
  15. 49 35
      lua/lvim/core/notify.lua
  16. 10 0
      lua/lvim/core/telescope/custom-finders.lua
  17. 7 3
      lua/lvim/core/treesitter.lua
  18. 8 14
      lua/lvim/core/which-key.lua
  19. 12 5
      lua/lvim/lsp/config.lua
  20. 6 121
      lua/lvim/lsp/handlers.lua
  21. 14 37
      lua/lvim/lsp/init.lua
  22. 1 0
      lua/lvim/lsp/manager.lua
  23. 1 10
      lua/lvim/lsp/null-ls/code_actions.lua
  24. 6 14
      lua/lvim/lsp/null-ls/formatters.lua
  25. 1 7
      lua/lvim/lsp/null-ls/init.lua
  26. 6 14
      lua/lvim/lsp/null-ls/linters.lua
  27. 2 10
      lua/lvim/lsp/peek.lua
  28. 18 3
      lua/lvim/lsp/providers/sumneko_lua.lua
  29. 10 0
      lua/lvim/lsp/utils.lua
  30. 29 24
      lua/lvim/plugins.lua
  31. 107 0
      lua/lvim/utils.lua
  32. 158 0
      lua/lvim/utils/git.lua
  33. 4 4
      lua/lvim/utils/hooks.lua
  34. 0 211
      lua/lvim/utils/init.lua
  35. 51 0
      tests/helpers.lua
  36. 8 1
      tests/minimal_init.lua
  37. 6 13
      tests/minimal_lsp.lua
  38. 0 0
      tests/specs/bootstrap_spec.lua
  39. 0 0
      tests/specs/config_loader_spec.lua
  40. 5 3
      tests/specs/lsp_spec.lua
  41. 0 0
      tests/specs/plugins_load_spec.lua
  42. 0 6
      utils/bin/lvim
  43. 7 0
      utils/bin/lvim.template
  44. 1 1
      utils/bin/test_runner.sh
  45. 2 3
      utils/installer/config.example.lua
  46. 18 20
      utils/installer/install.sh
  47. 25 21
      utils/installer/install_bin.sh

+ 3 - 3
.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.

+ 7 - 16
.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

+ 21 - 19
.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
-

+ 50 - 43
.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

+ 1 - 2
.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"

+ 9 - 5
Makefile

@@ -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)"

+ 3 - 1
README.md

@@ -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
 

+ 21 - 100
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

+ 7 - 4
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

+ 65 - 20
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 }, " ")

+ 1 - 1
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 = {

+ 19 - 23
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 {

+ 77 - 46
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

+ 2 - 3
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,
   },

+ 49 - 35
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

+ 10 - 0
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

+ 7 - 3
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

+ 8 - 14
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 = {

+ 12 - 5
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",
   },
 }

+ 6 - 121
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

+ 14 - 37
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

+ 1 - 0
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(),
   }
 

+ 1 - 10
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 = {}, {}
 

+ 6 - 14
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)

+ 1 - 7
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

+ 6 - 14
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)

+ 2 - 10
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(

+ 18 - 3
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)

+ 10 - 0
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

+ 29 - 24
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

+ 107 - 0
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

+ 158 - 0
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

+ 4 - 4
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

+ 0 - 211
lua/lvim/utils/init.lua

@@ -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

+ 51 - 0
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

+ 8 - 1
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()

+ 6 - 13
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

+ 0 - 0
tests/bootstrap_spec.lua → tests/specs/bootstrap_spec.lua


+ 0 - 0
tests/config_loader_spec.lua → tests/specs/config_loader_spec.lua


+ 5 - 3
tests/lsp_spec.lua → 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)

+ 0 - 0
tests/plugins_load_spec.lua → tests/specs/plugins_load_spec.lua


+ 0 - 6
utils/bin/lvim

@@ -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" "$@"

+ 7 - 0
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" "$@"

+ 1 - 1
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"

+ 2 - 3
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

+ 18 - 20
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() {

+ 25 - 21
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"