瀏覽代碼

refactor: auto-generate language configuration (#1584)

Refactor the monolithic `lvim.lang` design into a more modular approach.

IMPORTANT: run `:LvimUpdate` in order to generate the new ftplugin template files.
kylo252 3 年之前
父節點
當前提交
d01ba08eae
共有 98 個文件被更改,包括 1122 次插入1562 次删除
  1. 0 1
      ftplugin/asm.lua
  2. 0 1
      ftplugin/beancount.lua
  3. 0 1
      ftplugin/bicep.lua
  4. 0 4
      ftplugin/c.lua
  5. 0 1
      ftplugin/clojure.lua
  6. 0 1
      ftplugin/cmake.lua
  7. 0 1
      ftplugin/cpp.lua
  8. 0 1
      ftplugin/crystal.lua
  9. 0 1
      ftplugin/cs.lua
  10. 0 1
      ftplugin/css.lua
  11. 0 1
      ftplugin/d.lua
  12. 0 1
      ftplugin/dart.lua
  13. 0 1
      ftplugin/dockerfile.lua
  14. 0 10
      ftplugin/elixir.lua
  15. 0 1
      ftplugin/elm.lua
  16. 0 1
      ftplugin/erlang.lua
  17. 0 9
      ftplugin/euphoria3.lua
  18. 0 1
      ftplugin/fish.lua
  19. 0 1
      ftplugin/fortran.lua
  20. 0 1
      ftplugin/gdscript.lua
  21. 0 1
      ftplugin/go.lua
  22. 0 1
      ftplugin/graphql.lua
  23. 0 1
      ftplugin/haskell.lua
  24. 0 2
      ftplugin/html.lua
  25. 0 1
      ftplugin/java.lua
  26. 0 1
      ftplugin/javascript.lua
  27. 0 2
      ftplugin/javascriptreact.lua
  28. 0 1
      ftplugin/json.lua
  29. 0 1
      ftplugin/julia.lua
  30. 0 1
      ftplugin/kotlin.lua
  31. 0 1
      ftplugin/less.lua
  32. 0 1
      ftplugin/lua.lua
  33. 0 2
      ftplugin/netrw.lua
  34. 0 1
      ftplugin/nix.lua
  35. 0 1
      ftplugin/perl.lua
  36. 0 1
      ftplugin/php.lua
  37. 0 3
      ftplugin/ps1.lua
  38. 0 1
      ftplugin/puppet.lua
  39. 0 3
      ftplugin/python.lua
  40. 0 2
      ftplugin/r.lua
  41. 0 1
      ftplugin/rmd.lua
  42. 0 2
      ftplugin/ruby.lua
  43. 0 4
      ftplugin/rust.lua
  44. 0 1
      ftplugin/sass.lua
  45. 0 1
      ftplugin/sbt.lua
  46. 0 1
      ftplugin/scala.lua
  47. 0 1
      ftplugin/scss.lua
  48. 0 1
      ftplugin/sh.lua
  49. 0 1
      ftplugin/solidity.lua
  50. 0 1
      ftplugin/sql.lua
  51. 0 2
      ftplugin/svelte.lua
  52. 0 1
      ftplugin/swift.lua
  53. 0 1
      ftplugin/terraform.lua
  54. 0 1
      ftplugin/tex.lua
  55. 0 0
      ftplugin/thing.pp
  56. 0 1
      ftplugin/toml.lua
  57. 0 1
      ftplugin/typescript.lua
  58. 0 2
      ftplugin/typescriptreact.lua
  59. 0 1
      ftplugin/vim.lua
  60. 0 2
      ftplugin/vue.lua
  61. 0 1
      ftplugin/yaml.lua
  62. 0 1
      ftplugin/zig.lua
  63. 0 1
      ftplugin/zsh.lua
  64. 2 3
      init.lua
  65. 3 1
      lua/bootstrap.lua
  66. 1 1163
      lua/config/defaults.lua
  67. 100 0
      lua/config/init.lua
  68. 0 1
      lua/core/builtins/init.lua
  69. 28 2
      lua/core/cmp.lua
  70. 38 49
      lua/core/info.lua
  71. 1 0
      lua/core/log.lua
  72. 0 19
      lua/core/lspinstall.lua
  73. 0 3
      lua/core/lualine/components.lua
  74. 1 1
      lua/core/which-key.lua
  75. 27 0
      lua/lsp/config.lua
  76. 25 77
      lua/lsp/init.lua
  77. 0 31
      lua/lsp/kind.lua
  78. 82 0
      lua/lsp/manager.lua
  79. 8 22
      lua/lsp/null-ls/formatters.lua
  80. 18 36
      lua/lsp/null-ls/init.lua
  81. 8 22
      lua/lsp/null-ls/linters.lua
  82. 15 0
      lua/lsp/null-ls/services.lua
  83. 30 0
      lua/lsp/providers/jsonls.lua
  84. 19 0
      lua/lsp/providers/sumneko_lua.lua
  85. 26 0
      lua/lsp/providers/vuels.lua
  86. 98 0
      lua/lsp/templates.lua
  87. 49 8
      lua/lsp/utils.lua
  88. 1 6
      lua/plugins.lua
  89. 95 5
      lua/utils/init.lua
  90. 0 13
      tests/bootstrap_spec.lua
  91. 98 0
      tests/lsp_spec.lua
  92. 9 0
      tests/minimal_init.lua
  93. 34 0
      tests/plugins_load_spec.lua
  94. 9 0
      utils/bin/lvim.ps1
  95. 2 2
      utils/bin/test_runner.sh
  96. 14 1
      utils/installer/config.example.lua
  97. 280 0
      utils/installer/install.ps1
  98. 1 0
      utils/installer/uninstall.ps1

+ 0 - 1
ftplugin/asm.lua

@@ -1 +0,0 @@
-require("lsp").setup "asm"

+ 0 - 1
ftplugin/beancount.lua

@@ -1 +0,0 @@
-require("lsp").setup "beancount"

+ 0 - 1
ftplugin/bicep.lua

@@ -1 +0,0 @@
-require("lsp").setup "bicep"

+ 0 - 4
ftplugin/c.lua

@@ -1,4 +0,0 @@
-require("lsp").setup "c"
-
--- TODO get from dap
--- require("lang.c").dap()

+ 0 - 1
ftplugin/clojure.lua

@@ -1 +0,0 @@
-require("lsp").setup "clojure"

+ 0 - 1
ftplugin/cmake.lua

@@ -1 +0,0 @@
-require("lsp").setup "cmake"

+ 0 - 1
ftplugin/cpp.lua

@@ -1 +0,0 @@
-require("lsp").setup "cpp"

+ 0 - 1
ftplugin/crystal.lua

@@ -1 +0,0 @@
-require("lsp").setup "crystal"

+ 0 - 1
ftplugin/cs.lua

@@ -1 +0,0 @@
-require("lsp").setup "cs"

+ 0 - 1
ftplugin/css.lua

@@ -1 +0,0 @@
-require("lsp").setup "css"

+ 0 - 1
ftplugin/d.lua

@@ -1 +0,0 @@
-require("lsp").setup "d"

+ 0 - 1
ftplugin/dart.lua

@@ -1 +0,0 @@
-require("lsp").setup "dart"

+ 0 - 1
ftplugin/dockerfile.lua

@@ -1 +0,0 @@
-require("lsp").setup "dockerfile"

+ 0 - 10
ftplugin/elixir.lua

@@ -1,10 +0,0 @@
-require("lsp").setup "elixir"
-vim.api.nvim_buf_set_option(0, "commentstring", "# %s")
-
--- TODO: do we need this?
--- needed for the LSP to recognize elixir files (alternatively just use elixir-editors/vim-elixir)
--- vim.cmd [[
---   au BufRead,BufNewFile *.ex,*.exs set filetype=elixir
---   au BufRead,BufNewFile *.eex,*.leex,*.sface set filetype=eelixir
---   au BufRead,BufNewFile mix.lock set filetype=elixir
--- ]]

+ 0 - 1
ftplugin/elm.lua

@@ -1 +0,0 @@
-require("lsp").setup "elm"

+ 0 - 1
ftplugin/erlang.lua

@@ -1 +0,0 @@
-require("lsp").setup "erlang"

+ 0 - 9
ftplugin/euphoria3.lua

@@ -1,9 +0,0 @@
-require("lsp").setup "erlang"
-
--- TODO: do we need this?
--- needed for the LSP to recognize elixir files (alternatively just use elixir-editors/vim-elixir)
--- vim.cmd [[
---   au BufRead,BufNewFile *.ex,*.exs set filetype=elixir
---   au BufRead,BufNewFile *.eex,*.leex,*.sface set filetype=eelixir
---   au BufRead,BufNewFile mix.lock set filetype=elixir
--- ]]

+ 0 - 1
ftplugin/fish.lua

@@ -1 +0,0 @@
-require("lsp").setup "fish"

+ 0 - 1
ftplugin/fortran.lua

@@ -1 +0,0 @@
-require("lsp").setup "fortran"

+ 0 - 1
ftplugin/gdscript.lua

@@ -1 +0,0 @@
-require("lsp").setup "gdscript"

+ 0 - 1
ftplugin/go.lua

@@ -1 +0,0 @@
-require("lsp").setup "go"

+ 0 - 1
ftplugin/graphql.lua

@@ -1 +0,0 @@
-require("lsp").setup "graphql"

+ 0 - 1
ftplugin/haskell.lua

@@ -1 +0,0 @@
-require("lsp").setup "haskell"

+ 0 - 2
ftplugin/html.lua

@@ -1,2 +0,0 @@
-require("lsp").setup "html"
-require("lsp").setup "tailwindcss"

+ 0 - 1
ftplugin/java.lua

@@ -1 +0,0 @@
-require("lsp").setup "java"

+ 0 - 1
ftplugin/javascript.lua

@@ -1 +0,0 @@
-require("lsp").setup "javascript"

+ 0 - 2
ftplugin/javascriptreact.lua

@@ -1,2 +0,0 @@
-require("lsp").setup "javascriptreact"
-require("lsp").setup "tailwindcss"

+ 0 - 1
ftplugin/json.lua

@@ -1 +0,0 @@
-require("lsp").setup "json"

+ 0 - 1
ftplugin/julia.lua

@@ -1 +0,0 @@
-require("lsp").setup "julia"

+ 0 - 1
ftplugin/kotlin.lua

@@ -1 +0,0 @@
-require("lsp").setup "kotlin"

+ 0 - 1
ftplugin/less.lua

@@ -1 +0,0 @@
-css.lua

+ 0 - 1
ftplugin/lua.lua

@@ -1 +0,0 @@
-require("lsp").setup "lua"

+ 0 - 2
ftplugin/netrw.lua

@@ -1,2 +0,0 @@
-vim.cmd [[nmap <buffer> h -]]
-vim.cmd [[nmap <buffer> l <cr>]]

+ 0 - 1
ftplugin/nix.lua

@@ -1 +0,0 @@
-require("lsp").setup "nix"

+ 0 - 1
ftplugin/perl.lua

@@ -1 +0,0 @@
-require("lsp").setup "perl"

+ 0 - 1
ftplugin/php.lua

@@ -1 +0,0 @@
-require("lsp").setup "php"

+ 0 - 3
ftplugin/ps1.lua

@@ -1,3 +0,0 @@
-require("lsp").setup "ps1"
-
-vim.cmd [[setlocal ts=4 sw=4]]

+ 0 - 1
ftplugin/puppet.lua

@@ -1 +0,0 @@
-require("lsp").setup "puppet"

+ 0 - 3
ftplugin/python.lua

@@ -1,3 +0,0 @@
-require("lsp").setup "python"
--- TODO get from dap
--- require("lang.python").dap()

+ 0 - 2
ftplugin/r.lua

@@ -1,2 +0,0 @@
--- R -e 'install.packages("languageserver",repos = "http://cran.us.r-project.org")'
-require("lsp").setup "r"

+ 0 - 1
ftplugin/rmd.lua

@@ -1 +0,0 @@
-r.lua

+ 0 - 2
ftplugin/ruby.lua

@@ -1,2 +0,0 @@
--- also support sorbet
-require("lsp").setup "ruby"

+ 0 - 4
ftplugin/rust.lua

@@ -1,4 +0,0 @@
-require("lsp").setup "rust"
-
--- TODO get from dap
--- require("lang.rust").dap()

+ 0 - 1
ftplugin/sass.lua

@@ -1 +0,0 @@
-css.lua

+ 0 - 1
ftplugin/sbt.lua

@@ -1 +0,0 @@
-scala.lua

+ 0 - 1
ftplugin/scala.lua

@@ -1 +0,0 @@
-require("lsp").setup "scala"

+ 0 - 1
ftplugin/scss.lua

@@ -1 +0,0 @@
-css.lua

+ 0 - 1
ftplugin/sh.lua

@@ -1 +0,0 @@
-require("lsp").setup "sh"

+ 0 - 1
ftplugin/solidity.lua

@@ -1 +0,0 @@
-require("lsp").setup "solidity"

+ 0 - 1
ftplugin/sql.lua

@@ -1 +0,0 @@
-require("lsp").setup "sql"

+ 0 - 2
ftplugin/svelte.lua

@@ -1,2 +0,0 @@
-require("lsp").setup "svelte"
-require("lsp").setup "tailwindcss"

+ 0 - 1
ftplugin/swift.lua

@@ -1 +0,0 @@
-require("lsp").setup "swift"

+ 0 - 1
ftplugin/terraform.lua

@@ -1 +0,0 @@
-require("lsp").setup "terraform"

+ 0 - 1
ftplugin/tex.lua

@@ -1 +0,0 @@
-require("lsp").setup "tex"

+ 0 - 0
ftplugin/thing.pp


+ 0 - 1
ftplugin/toml.lua

@@ -1 +0,0 @@
-vim.cmd [[setlocal commentstring=#%s]]

+ 0 - 1
ftplugin/typescript.lua

@@ -1 +0,0 @@
-require("lsp").setup "typescript"

+ 0 - 2
ftplugin/typescriptreact.lua

@@ -1,2 +0,0 @@
-require("lsp").setup "typescript"
-require("lsp").setup "tailwindcss"

+ 0 - 1
ftplugin/vim.lua

@@ -1 +0,0 @@
-require("lsp").setup "vim"

+ 0 - 2
ftplugin/vue.lua

@@ -1,2 +0,0 @@
-require("lsp").setup "vue"
-require("lsp").setup "tailwindcss"

+ 0 - 1
ftplugin/yaml.lua

@@ -1 +0,0 @@
-require("lsp").setup "yaml"

+ 0 - 1
ftplugin/zig.lua

@@ -1 +0,0 @@
-require("lsp").setup "zig"

+ 0 - 1
ftplugin/zsh.lua

@@ -1 +0,0 @@
-require("lsp").setup "sh"

+ 2 - 3
init.lua

@@ -18,10 +18,9 @@ Log:debug "Starting LunarVim"
 vim.g.colors_name = lvim.colorscheme -- Colorscheme must get called after plugins are loaded or it will break new installs.
 vim.cmd("colorscheme " .. lvim.colorscheme)
 
-require("utils").toggle_autoformat()
 local commands = require "core.commands"
 commands.load(commands.defaults)
 
-require("lsp").global_setup()
-
 require("keymappings").setup()
+
+require("lsp").setup()

+ 3 - 1
lua/bootstrap.lua

@@ -85,9 +85,10 @@ function M:init()
     vim.cmd("set spellfile=" .. join_paths(self.config_dir, "spell", "en.utf-8.add"))
   end
 
+  vim.fn.mkdir(vim.fn.stdpath "cache", "p")
+
   -- FIXME: currently unreliable in unit-tests
   if not os.getenv "LVIM_TEST_ENV" then
-    vim.fn.mkdir(vim.fn.stdpath "cache", "p")
     require("impatient").setup {
       path = vim.fn.stdpath "cache" .. "/lvim_cache",
       enable_profiling = true,
@@ -112,6 +113,7 @@ end
 function M:update()
   M:update_repo()
   M:reset_cache()
+  require("lsp.templates").generate_templates()
   vim.schedule(function()
     -- TODO: add a changelog
     vim.notify("Update complete", vim.log.levels.INFO)

+ 1 - 1163
lua/config/defaults.lua

@@ -1,7 +1,5 @@
 local home_dir = vim.loop.os_homedir()
 local utils = require "utils"
--- FIXME: stop using hard-coded paths for LspInstall
-local ls_install_prefix = vim.fn.stdpath "data" .. "/lspinstall"
 
 lvim = {
   leader = "space",
@@ -30,1170 +28,10 @@ lvim = {
       },
     },
   },
-
-  lsp = {
-    completion = {
-      item_kind = {
-        "   (Text) ",
-        "   (Method)",
-        "   (Function)",
-        "   (Constructor)",
-        "   (Field)",
-        "   (Variable)",
-        "   (Class)",
-        " ﰮ  (Interface)",
-        "   (Module)",
-        "   (Property)",
-        " 塞 (Unit)",
-        "   (Value)",
-        " 練 (Enum)",
-        "   (Keyword)",
-        "   (Snippet)",
-        "   (Color)",
-        "   (File)",
-        "   (Reference)",
-        "   (Folder)",
-        "   (EnumMember)",
-        " ﲀ  (Constant)",
-        "   (Struct)",
-        "   (Event)",
-        "   (Operator)",
-        "   (TypeParameter)",
-      },
-    },
-    diagnostics = {
-      signs = {
-        active = true,
-        values = {
-          { name = "LspDiagnosticsSignError", text = "" },
-          { name = "LspDiagnosticsSignWarning", text = "" },
-          { name = "LspDiagnosticsSignHint", text = "" },
-          { name = "LspDiagnosticsSignInformation", text = "" },
-        },
-      },
-      virtual_text = {
-        prefix = "",
-        spacing = 0,
-      },
-      update_in_insert = false,
-      underline = true,
-      severity_sort = true,
-    },
-    override = {},
-    document_highlight = true,
-    popup_border = "single",
-    on_attach_callback = nil,
-    on_init_callback = nil,
-    null_ls = {
-      setup = {},
-    },
-  },
-
   plugins = {
     -- use config.lua for this not put here
   },
 
   autocommands = {},
-}
-
-local schemas = nil
-local status_ok, jsonls_settings = pcall(require, "nlspsettings.jsonls")
-if status_ok then
-  schemas = jsonls_settings.get_default_schemas()
-end
-
--- TODO move all of this into lang specific files, only require when using
-lvim.lang = {
-  asm = {
-    formatters = {
-      -- {
-      --   exe = "asmfmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "",
-      setup = {},
-    },
-  },
-  beancount = {
-    formatters = {
-      -- {
-      --   exe = "bean_format",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "beancount",
-      setup = {
-        cmd = { "beancount-langserver" },
-      },
-    },
-  },
-  bicep = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "bicep",
-      setup = {
-        cmd = {
-          "dotnet",
-          ls_install_prefix .. "/bicep/Bicep.LangServer.dll",
-        },
-        filetypes = { "bicep" },
-      },
-    },
-  },
-  c = {
-    formatters = {
-      -- {
-      --   exe = "clang_format",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "uncrustify",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "clangd",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/cpp/clangd/bin/clangd",
-          "--background-index",
-          "--header-insertion=never",
-          "--cross-file-rename",
-          "--clang-tidy",
-          "--clang-tidy-checks=-*,llvm-*,clang-analyzer-*",
-        },
-      },
-    },
-  },
-  cpp = {
-    formatters = {
-      -- {
-      --   exe = "clang_format",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "uncrustify",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "clangd",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/cpp/clangd/bin/clangd",
-          "--background-index",
-          "--header-insertion=never",
-          "--cross-file-rename",
-          "--clang-tidy",
-          "--clang-tidy-checks=-*,llvm-*,clang-analyzer-*",
-        },
-      },
-    },
-  },
-  crystal = {
-    formatters = {
-      -- {
-      --   exe = "crystal_format",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "crystalline",
-      setup = {
-        cmd = { "crystalline" },
-      },
-    },
-  },
-  cs = {
-    formatters = {
-      -- {
-      --   exe = "clang_format ",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "uncrustify",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "omnisharp",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/csharp/omnisharp/run",
-          "--languageserver",
-          "--hostPID",
-          tostring(vim.fn.getpid()),
-        },
-      },
-    },
-  },
-  cmake = {
-    formatters = {
-      -- {
-      --   exe = "cmake_format",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "cmake",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/cmake/venv/bin/cmake-language-server",
-        },
-      },
-    },
-  },
-  clojure = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "clojure_lsp",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/clojure/clojure-lsp",
-        },
-      },
-    },
-  },
-  css = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "cssls",
-      setup = {
-        cmd = {
-          "node",
-          ls_install_prefix .. "/css/vscode-css/css-language-features/server/dist/node/cssServerMain.js",
-          "--stdio",
-        },
-      },
-    },
-  },
-  less = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "cssls",
-      setup = {
-        cmd = {
-          "node",
-          ls_install_prefix .. "/css/vscode-css/css-language-features/server/dist/node/cssServerMain.js",
-          "--stdio",
-        },
-      },
-    },
-  },
-  d = {
-    formatters = {
-      -- {
-      --   exe = "dfmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "serve_d",
-      setup = {
-        cmd = { "serve-d" },
-      },
-    },
-  },
-  dart = {
-    formatters = {
-      -- {
-      --   exe = "dart_format",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "dartls",
-      setup = {
-        cmd = {
-          "dart",
-          "/usr/lib/dart/bin/snapshots/analysis_server.dart.snapshot",
-          "--lsp",
-        },
-      },
-    },
-  },
-  dockerfile = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "dockerls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/dockerfile/node_modules/.bin/docker-langserver",
-          "--stdio",
-        },
-      },
-    },
-  },
-  elixir = {
-    formatters = {
-      -- {
-      --   exe = "mix",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "elixirls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/elixir/elixir-ls/language_server.sh",
-        },
-      },
-    },
-  },
-  elm = {
-    formatters = {
-      -- {
-      --   exe = "elm_format",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "elmls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/elm/node_modules/.bin/elm-language-server",
-        },
-        -- init_options = {
-        -- elmAnalyseTrigger = "change",
-        -- elmFormatPath = ls_install_prefix .. "/elm/node_modules/.bin/elm-format",
-        -- elmPath = ls_install_prefix .. "/elm/node_modules/.bin/",
-        -- elmTestPath = ls_install_prefix .. "/elm/node_modules/.bin/elm-test",
-        -- },
-      },
-    },
-  },
-  erlang = {
-    formatters = {
-      -- {
-      --   exe = "erlfmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "erlangls",
-      setup = {
-        cmd = {
-          "erlang_ls",
-        },
-      },
-    },
-  },
-  emmet = { active = false },
-  fish = {
-    formatters = {
-      -- {
-      --   exe = "fish_indent",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "",
-      setup = {},
-    },
-  },
-  fortran = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "fortls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/fortran/venv/bin/fortls",
-        },
-      },
-    },
-  },
-  go = {
-    formatters = {
-      -- {
-      --   exe = "gofmt",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "goimports",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "gofumpt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "gopls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/go/gopls",
-        },
-      },
-    },
-  },
-  graphql = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "graphql",
-      setup = {
-        cmd = {
-          "graphql-lsp",
-          "server",
-          "-m",
-          "stream",
-        },
-      },
-    },
-  },
-  haskell = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "hls",
-      setup = {
-        cmd = { ls_install_prefix .. "/haskell/hls" },
-      },
-    },
-  },
-  html = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "html",
-      setup = {
-        cmd = {
-          "node",
-          ls_install_prefix .. "/html/vscode-html/html-language-features/server/dist/node/htmlServerMain.js",
-          "--stdio",
-        },
-      },
-    },
-  },
-  java = {
-    formatters = {
-      -- {
-      --   exe = "clang_format",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "uncrustify",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "jdtls",
-      setup = {
-        cmd = { ls_install_prefix .. "/java/jdtls.sh" },
-      },
-    },
-  },
-  json = {
-    formatters = {
-      -- {
-      --   exe = "json_tool",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "jsonls",
-      setup = {
-        cmd = {
-          "node",
-          ls_install_prefix .. "/json/vscode-json/json-language-features/server/dist/node/jsonServerMain.js",
-          "--stdio",
-        },
-        settings = {
-          json = {
-            schemas = schemas,
-            --   = {
-            --   {
-            --     fileMatch = { "package.json" },
-            --     url = "https://json.schemastore.org/package.json",
-            --   },
-            -- },
-          },
-        },
-        commands = {
-          Format = {
-            function()
-              vim.lsp.buf.range_formatting({}, { 0, 0 }, { vim.fn.line "$", 0 })
-            end,
-          },
-        },
-      },
-    },
-  },
-  julia = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "julials",
-      setup = {
-        {
-          "julia",
-          "--startup-file=no",
-          "--history-file=no",
-          -- self.runtime_dir .. "lvim/utils/julia/run.jl",
-        },
-      },
-    },
-  },
-  kotlin = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "kotlin_language_server",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/kotlin/server/bin/kotlin-language-server",
-        },
-        root_dir = function(fname)
-          local util = require "lspconfig/util"
-
-          local root_files = {
-            "settings.gradle", -- Gradle (multi-project)
-            "settings.gradle.kts", -- Gradle (multi-project)
-            "build.xml", -- Ant
-            "pom.xml", -- Maven
-          }
-
-          local fallback_root_files = {
-            "build.gradle", -- Gradle
-            "build.gradle.kts", -- Gradle
-          }
-          return util.root_pattern(unpack(root_files))(fname) or util.root_pattern(unpack(fallback_root_files))(fname)
-        end,
-      },
-    },
-  },
-  lua = {
-    formatters = {
-      -- {
-      --   exe = "stylua",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "lua_format",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "sumneko_lua",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/lua/sumneko-lua-language-server",
-          "-E",
-          ls_install_prefix .. "/lua/main.lua",
-        },
-        settings = {
-          Lua = {
-            diagnostics = {
-              -- Get the language server to recognize the `vim` global
-              globals = { "vim", "lvim" },
-            },
-            workspace = {
-              -- Make the server aware of Neovim runtime files
-              library = {
-                [require("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,
-            },
-          },
-        },
-      },
-    },
-  },
-  nginx = {
-    formatters = {
-      -- {
-      --   exe = "nginx_beautifier",
-      --   args = {
-      --     provider = "",
-      --     setup = {},
-      --   },
-      -- },
-    },
-    linters = {},
-    lsp = {},
-  },
-  perl = {
-    formatters = {
-      -- {
-      --   exe = "perltidy",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "",
-      setup = {},
-    },
-  },
-  solidity = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "solang",
-      setup = {
-        cmd = { "solang", "--language-server" },
-      },
-    },
-  },
-  sql = {
-    formatters = {
-      -- {
-      --   exe = "sqlformat",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "sqls",
-      setup = {
-        cmd = { "sqls" },
-      },
-    },
-  },
-  php = {
-    formatters = {
-      -- {
-      --   exe = "phpcbf",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "intelephense",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/php/node_modules/.bin/intelephense",
-          "--stdio",
-        },
-        filetypes = { "php", "phtml" },
-        settings = {
-          intelephense = {
-            environment = {
-              phpVersion = "7.4",
-            },
-          },
-        },
-      },
-    },
-  },
-  puppet = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "puppet",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/puppet/puppet-editor-services/puppet-languageserver",
-          "--stdio",
-        },
-      },
-    },
-  },
-  javascript = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettier_d_slim",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-    },
-    -- @usage can be {"eslint"} or {"eslint_d"}
-    linters = {},
-    lsp = {
-      provider = "tsserver",
-      setup = {
-        cmd = {
-          -- TODO:
-          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server",
-          "--stdio",
-        },
-      },
-    },
-  },
-  javascriptreact = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettier_d_slim",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "tsserver",
-      setup = {
-        cmd = {
-          -- TODO:
-          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server",
-          "--stdio",
-        },
-      },
-    },
-  },
-  python = {
-    formatters = {
-      -- {
-      --   exe = "yapf",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "isort",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "pyright",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/python/node_modules/.bin/pyright-langserver",
-          "--stdio",
-        },
-      },
-    },
-  },
-  -- R -e 'install.packages("formatR",repos = "http://cran.us.r-project.org")'
-  -- R -e 'install.packages("readr",repos = "http://cran.us.r-project.org")'
-  r = {
-    formatters = {
-      -- {
-      --   exe = "format_r",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "r_language_server",
-      setup = {
-        cmd = {
-          "R",
-          "--slave",
-          "-e",
-          "languageserver::run()",
-        },
-      },
-    },
-  },
-  ruby = {
-    formatters = {
-      -- {
-      --   exe = "rufo",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "solargraph",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/ruby/solargraph/solargraph",
-          "stdio",
-        },
-        filetypes = { "ruby" },
-        init_options = {
-          formatting = true,
-        },
-        root_dir = function(fname)
-          local util = require("lspconfig").util
-          return util.root_pattern("Gemfile", ".git")(fname)
-        end,
-        settings = {
-          solargraph = {
-            diagnostics = true,
-          },
-        },
-      },
-    },
-  },
-  rust = {
-    formatters = {
-      -- {
-      --   exe = "rustfmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "rust_analyzer",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/rust/rust-analyzer",
-        },
-      },
-    },
-  },
-  scala = {
-    formatters = {
-      -- {
-      --   exe = "scalafmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "metals",
-      setup = {},
-    },
-  },
-  sh = {
-    formatters = {
-      -- {
-      --   exe = "shfmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "bashls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/bash/node_modules/.bin/bash-language-server",
-          "start",
-        },
-      },
-    },
-  },
-  svelte = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "svelte",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/svelte/node_modules/.bin/svelteserver",
-          "--stdio",
-        },
-      },
-    },
-  },
-  swift = {
-    formatters = {
-      -- {
-      --   exe = "swiftformat",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "sourcekit",
-      setup = {
-        cmd = {
-          "xcrun",
-          "sourcekit-lsp",
-        },
-      },
-    },
-  },
-  tailwindcss = {
-    lsp = {
-      active = false,
-      provider = "tailwindcss",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/tailwindcss/node_modules/.bin/tailwindcss-language-server",
-          "--stdio",
-        },
-      },
-    },
-  },
-  terraform = {
-    formatters = {
-      -- {
-      --   exe = "terraform_fmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "terraformls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/terraform/terraform-ls",
-          "serve",
-        },
-      },
-    },
-  },
-  tex = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "texlab",
-      setup = {
-        cmd = { ls_install_prefix .. "/latex/texlab" },
-      },
-    },
-  },
-  typescript = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettier_d_slim",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "tsserver",
-      setup = {
-        cmd = {
-          -- TODO:
-          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server",
-          "--stdio",
-        },
-      },
-    },
-  },
-  typescriptreact = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettier_d_slim",
-      --   args = {},
-      -- },
-    },
-    -- @usage can be {"eslint"} or {"eslint_d"}
-    linters = {},
-    lsp = {
-      provider = "tsserver",
-      setup = {
-        cmd = {
-          -- TODO:
-          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server",
-          "--stdio",
-        },
-      },
-    },
-  },
-  vim = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "vimls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/vim/node_modules/.bin/vim-language-server",
-          "--stdio",
-        },
-      },
-    },
-  },
-  vue = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettier_d_slim",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "vuels",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/vue/node_modules/.bin/vls",
-        },
-        root_dir = function(fname)
-          local util = require "lspconfig/util"
-          return util.root_pattern "package.json"(fname) or util.root_pattern "vue.config.js"(fname) or vim.fn.getcwd()
-        end,
-        init_options = {
-          config = {
-            vetur = {
-              completion = {
-                autoImport = true,
-                tagCasing = "kebab",
-                useScaffoldSnippets = true,
-              },
-              useWorkspaceDependencies = true,
-              validation = {
-                script = true,
-                style = true,
-                template = true,
-              },
-            },
-          },
-        },
-      },
-    },
-  },
-  yaml = {
-    formatters = {
-      -- {
-      --   exe = "prettier",
-      --   args = {},
-      -- },
-      -- {
-      --   exe = "prettierd",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "yamlls",
-      setup = {
-        cmd = {
-          ls_install_prefix .. "/yaml/node_modules/.bin/yaml-language-server",
-          "--stdio",
-        },
-      },
-    },
-  },
-  zig = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "zls",
-      setup = {
-        cmd = {
-          "zls",
-        },
-      },
-    },
-  },
-  gdscript = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "gdscript",
-      setup = {
-        cmd = {
-          "nc",
-          "localhost",
-          "6008",
-        },
-      },
-    },
-  },
-  ps1 = {
-    formatters = {},
-    linters = {},
-    lsp = {
-      provider = "powershell_es",
-      setup = {
-        bundle_path = "",
-      },
-    },
-  },
-  nix = {
-    formatters = {
-      -- {
-      --   exe = "nixfmt",
-      --   args = {},
-      -- },
-    },
-    linters = {},
-    lsp = {
-      provider = "rnix",
-      setup = {
-        cmd = { "rnix-lsp" },
-        filetypes = { "nix" },
-        init_options = {},
-        settings = {},
-        root_dir = function(fname)
-          local util = require "lspconfig/util"
-          return util.root_pattern ".git"(fname) or vim.fn.getcwd()
-        end,
-      },
-    },
-  },
+  lang = {},
 }

+ 100 - 0
lua/config/init.lua

@@ -22,6 +22,106 @@ function M:init(opts)
 
   local settings = require "config.settings"
   settings.load_options()
+
+  local lvim_lsp_config = require "lsp.config"
+  lvim.lsp = vim.deepcopy(lvim_lsp_config)
+
+  local supported_languages = {
+    "asm",
+    "bash",
+    "beancount",
+    "bibtex",
+    "bicep",
+    "c",
+    "c_sharp",
+    "clojure",
+    "cmake",
+    "comment",
+    "commonlisp",
+    "cpp",
+    "crystal",
+    "cs",
+    "css",
+    "cuda",
+    "d",
+    "dart",
+    "dockerfile",
+    "dot",
+    "elixir",
+    "elm",
+    "emmet",
+    "erlang",
+    "fennel",
+    "fish",
+    "fortran",
+    "gdscript",
+    "glimmer",
+    "go",
+    "gomod",
+    "graphql",
+    "haskell",
+    "hcl",
+    "heex",
+    "html",
+    "java",
+    "javascript",
+    "javascriptreact",
+    "jsdoc",
+    "json",
+    "json5",
+    "jsonc",
+    "julia",
+    "kotlin",
+    "latex",
+    "ledger",
+    "less",
+    "lua",
+    "markdown",
+    "nginx",
+    "nix",
+    "ocaml",
+    "ocaml_interface",
+    "perl",
+    "php",
+    "pioasm",
+    "ps1",
+    "puppet",
+    "python",
+    "ql",
+    "query",
+    "r",
+    "regex",
+    "rst",
+    "ruby",
+    "rust",
+    "scala",
+    "scss",
+    "sh",
+    "solidity",
+    "sparql",
+    "sql",
+    "supercollider",
+    "surface",
+    "svelte",
+    "swift",
+    "tailwindcss",
+    "terraform",
+    "tex",
+    "tlaplus",
+    "toml",
+    "tsx",
+    "turtle",
+    "typescript",
+    "typescriptreact",
+    "verilog",
+    "vim",
+    "vue",
+    "yaml",
+    "yang",
+    "zig",
+  }
+
+  require("lsp.manager").init_defaults(supported_languages)
 end
 
 --- Override the configuration with a user provided one

+ 0 - 1
lua/core/builtins/init.lua

@@ -15,7 +15,6 @@ local builtins = {
   "core.bufferline",
   "core.autopairs",
   "core.comment",
-  "core.lspinstall",
   "core.lualine",
 }
 

+ 28 - 2
lua/core/cmp.lua

@@ -35,9 +35,35 @@ M.config = function()
       select = true,
     },
     formatting = {
+      kind_icons = {
+        Class = " ",
+        Color = " ",
+        Constant = "ﲀ ",
+        Constructor = " ",
+        Enum = "練",
+        EnumMember = " ",
+        Event = " ",
+        Field = " ",
+        File = "",
+        Folder = " ",
+        Function = " ",
+        Interface = "ﰮ ",
+        Keyword = " ",
+        Method = " ",
+        Module = " ",
+        Operator = "",
+        Property = " ",
+        Reference = " ",
+        Snippet = " ",
+        Struct = " ",
+        Text = " ",
+        TypeParameter = " ",
+        Unit = "塞",
+        Value = " ",
+        Variable = " ",
+      },
       format = function(entry, vim_item)
-        local icons = require("lsp.kind").icons
-        vim_item.kind = icons[vim_item.kind]
+        vim_item.kind = lvim.builtin.cmp.formatting.kind_icons[vim_item.kind]
         vim_item.menu = ({
           nvim_lsp = "(LSP)",
           emoji = "(Emoji)",

+ 38 - 49
lua/core/info.lua

@@ -10,6 +10,7 @@ local M = {
 }
 
 local fmt = string.format
+local text = require "interface.text"
 
 local function str_list(list)
   return fmt("[ %s ]", table.concat(list, ", "))
@@ -65,44 +66,55 @@ local function tbl_set_highlight(terms, highlight_group)
   end
 end
 
+local function make_client_info(client)
+  local client_enabled_caps = require("lsp.utils").get_ls_capabilities(client.id)
+  local name = client.name
+  local id = client.id
+  local document_formatting = client.resolved_capabilities.document_formatting
+  local client_info = {
+    fmt("* Name:                 %s", name),
+    fmt("* Id:                   %s", tostring(id)),
+    fmt("* Supports formatting:  %s", tostring(document_formatting)),
+  }
+  if not vim.tbl_isempty(client_enabled_caps) then
+    local caps_text = "* Capabilities list:    "
+    local caps_text_len = caps_text:len()
+    local enabled_caps = text.format_table(client_enabled_caps, 3, " | ")
+    enabled_caps = text.shift_right(enabled_caps, caps_text_len)
+    enabled_caps[1] = fmt("%s%s", caps_text, enabled_caps[1]:sub(caps_text_len + 1))
+    vim.list_extend(client_info, enabled_caps)
+  end
+
+  return client_info
+end
+
 function M.toggle_popup(ft)
   local lsp_utils = require "lsp.utils"
-  local client = lsp_utils.get_active_client_by_ft(ft)
-  local is_client_active = false
-  local client_enabled_caps = {}
-  local client_name = ""
-  local client_id = 0
-  local document_formatting = false
-  if client ~= nil then
-    is_client_active = not client.is_stopped()
-    client_enabled_caps = require("lsp").get_ls_capabilities(client.id)
-    client_name = client.name
-    client_id = client.id
-    document_formatting = client.resolved_capabilities.document_formatting
-  end
+  local clients = lsp_utils.get_active_client_by_ft(ft)
+  local client_names = {}
 
   local header = {
     fmt("Detected filetype:      %s", ft),
     fmt("Treesitter active:      %s", tostring(next(vim.treesitter.highlighter.active) ~= nil)),
   }
 
-  local text = require "interface.text"
   local lsp_info = {
     "Language Server Protocol (LSP) info",
-    fmt("* Associated server:    %s", client_name),
-    fmt("* Active:               %s (id: %d)", tostring(is_client_active), client_id),
-    fmt("* Supports formatting:  %s", tostring(document_formatting)),
+    fmt "* Associated server(s):",
   }
-  if not vim.tbl_isempty(client_enabled_caps) then
-    local caps_text = "* Capabilities list:    "
-    local caps_text_len = caps_text:len()
-    local enabled_caps = text.format_table(client_enabled_caps, 3, " | ")
-    enabled_caps = text.shift_right(enabled_caps, caps_text_len)
-    enabled_caps[1] = fmt("%s%s", caps_text, enabled_caps[1]:sub(caps_text_len + 1))
-    vim.list_extend(lsp_info, enabled_caps)
+
+  for _, client in pairs(clients) do
+    vim.list_extend(lsp_info, make_client_info(client))
+    table.insert(client_names, client.name)
   end
-  local null_ls = require "lsp.null-ls"
-  local registered_providers = null_ls.list_supported_provider_names(ft)
+
+  local null_formatters = require "lsp.null-ls.formatters"
+  local null_linters = require "lsp.null-ls.linters"
+  local registered_formatters = null_formatters.list_supported_names(ft)
+  local registered_linters = null_linters.list_supported_names(ft)
+  local registered_providers = {}
+  vim.list_extend(registered_providers, registered_formatters)
+  vim.list_extend(registered_providers, registered_linters)
   local registered_count = vim.tbl_count(registered_providers)
   local null_ls_info = {
     "Formatters and linters",
@@ -113,24 +125,6 @@ function M.toggle_popup(ft)
     ),
   }
 
-  local null_formatters = require "lsp.null-ls.formatters"
-  local missing_formatters = null_formatters.list_unsupported_names(ft)
-  local missing_formatters_status = {}
-  if not vim.tbl_isempty(missing_formatters) then
-    missing_formatters_status = {
-      fmt("* Missing formatters:   %s", table.concat(missing_formatters, "  , ") .. "  "),
-    }
-  end
-
-  local null_linters = require "lsp.null-ls.linters"
-  local missing_linters = null_linters.list_unsupported_names(ft)
-  local missing_linters_status = {}
-  if not vim.tbl_isempty(missing_linters) then
-    missing_linters_status = {
-      fmt("* Missing linters:      %s", table.concat(missing_linters, "  , ") .. "  "),
-    }
-  end
-
   local content_provider = function(popup)
     local content = {}
 
@@ -143,8 +137,6 @@ function M.toggle_popup(ft)
       lsp_info,
       { "" },
       null_ls_info,
-      missing_formatters_status,
-      missing_linters_status,
       { "" },
       { "" },
       get_formatter_suggestion_msg(ft),
@@ -167,11 +159,8 @@ function M.toggle_popup(ft)
     vim.cmd 'let m=matchadd("string", "true")'
     vim.cmd 'let m=matchadd("error", "false")'
     tbl_set_highlight(registered_providers, "LvimInfoIdentifier")
-    tbl_set_highlight(missing_formatters, "LvimInfoIdentifier")
-    tbl_set_highlight(missing_linters, "LvimInfoIdentifier")
     -- tbl_set_highlight(require("lsp.null-ls.formatters").list_available(ft), "LvimInfoIdentifier")
     -- tbl_set_highlight(require("lsp.null-ls.linters").list_available(ft), "LvimInfoIdentifier")
-    vim.cmd('let m=matchadd("LvimInfoIdentifier", "' .. client_name .. '")')
   end
 
   local Popup = require("interface.popup"):new {

+ 1 - 0
lua/core/log.lua

@@ -8,6 +8,7 @@ function Log:add_entry(msg, level)
   if self.__handle then
     -- plenary uses lower-case log levels
     self.__handle[level:lower()](msg)
+    return
   end
   local status_ok, plenary = pcall(require, "plenary")
   if status_ok then

+ 0 - 19
lua/core/lspinstall.lua

@@ -1,19 +0,0 @@
-local M = {}
-
-M.config = function()
-  lvim.builtin.lspinstall = {
-    active = true,
-    on_config_done = nil,
-  }
-end
-
-M.setup = function()
-  local lspinstall = require "lspinstall"
-  lspinstall.setup()
-
-  if lvim.builtin.lspinstall.on_config_done then
-    lvim.builtin.lspinstall.on_config_done(lspinstall)
-  end
-end
-
-return M

+ 0 - 3
lua/core/lualine/components.lua

@@ -96,14 +96,11 @@ return {
       local buf_client_names = {}
 
       -- add client
-      local utils = require "lsp.utils"
-      local active_client = utils.get_active_client_by_ft(buf_ft)
       for _, client in pairs(buf_clients) do
         if client.name ~= "null-ls" then
           table.insert(buf_client_names, client.name)
         end
       end
-      vim.list_extend(buf_client_names, active_client or {})
 
       -- add formatter
       local formatters = require "lsp.null-ls.formatters"

+ 1 - 1
lua/core/which-key.lua

@@ -148,9 +148,9 @@ M.config = function()
           "<cmd>Telescope lsp_workspace_diagnostics<cr>",
           "Workspace Diagnostics",
         },
-        -- f = { "<cmd>silent FormatWrite<cr>", "Format" },
         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>",
           "Next Diagnostic",

+ 27 - 0
lua/lsp/config.lua

@@ -0,0 +1,27 @@
+return {
+  templates_dir = join_paths(get_runtime_dir(), "site", "after", "ftplugin"),
+  diagnostics = {
+    signs = {
+      active = true,
+      values = {
+        { name = "LspDiagnosticsSignError", text = "" },
+        { name = "LspDiagnosticsSignWarning", text = "" },
+        { name = "LspDiagnosticsSignHint", text = "" },
+        { name = "LspDiagnosticsSignInformation", text = "" },
+      },
+    },
+    virtual_text = {
+      prefix = "",
+      spacing = 0,
+    },
+    update_in_insert = false,
+    underline = true,
+    severity_sort = true,
+  },
+  override = {},
+  document_highlight = true,
+  popup_border = "single",
+  on_attach_callback = nil,
+  on_init_callback = nil,
+  automatic_servers_installation = true,
+}

+ 25 - 77
lua/lsp/init.lua

@@ -1,5 +1,6 @@
 local M = {}
 local Log = require "core.log"
+local utils = require "utils"
 
 local function lsp_highlight_document(client)
   if lvim.lsp.document_highlight == false then
@@ -61,48 +62,12 @@ function M.common_capabilities()
   return capabilities
 end
 
-function M.get_ls_capabilities(client_id)
-  local client
-  if not client_id then
-    local buf_clients = vim.lsp.buf_get_clients()
-    for _, buf_client in ipairs(buf_clients) do
-      if buf_client.name ~= "null-ls" then
-        client_id = buf_client.id
-        break
-      end
-    end
-  end
-  if not client_id then
-    error "Unable to determine client_id"
-  end
-
-  client = vim.lsp.get_client_by_id(tonumber(client_id))
-
-  local enabled_caps = {}
-
-  for k, v in pairs(client.resolved_capabilities) do
-    if v == true then
-      table.insert(enabled_caps, k)
-    end
-  end
-
-  return enabled_caps
-end
-
 function M.common_on_init(client, bufnr)
   if lvim.lsp.on_init_callback then
     lvim.lsp.on_init_callback(client, bufnr)
     Log:debug "Called lsp.on_init_callback"
     return
   end
-
-  local formatters = lvim.lang[vim.bo.filetype].formatters
-  if not vim.tbl_isempty(formatters) and formatters[1]["exe"] ~= nil and formatters[1].exe ~= "" then
-    client.resolved_capabilities.document_formatting = false
-    Log:debug(
-      string.format("Overriding language server [%s] with format provider [%s]", client.name, formatters[1].exe)
-    )
-  end
 end
 
 function M.common_on_attach(client, bufnr)
@@ -112,63 +77,46 @@ function M.common_on_attach(client, bufnr)
   end
   lsp_highlight_document(client)
   add_lsp_buffer_keybindings(bufnr)
-  require("lsp.null-ls").setup(vim.bo.filetype)
 end
 
-function M.setup(lang)
-  local lsp_utils = require "lsp.utils"
-  local lsp = lvim.lang[lang].lsp
-  if (lsp.active ~= nil and not lsp.active) or lsp_utils.is_client_active(lsp.provider) then
-    return
-  end
-
-  local overrides = lvim.lsp.override
-  if type(overrides) == "table" then
-    if vim.tbl_contains(overrides, lang) then
-      return
-    end
+local function bootstrap_nlsp(opts)
+  opts = opts or {}
+  local lsp_settings_status_ok, lsp_settings = pcall(require, "nlspsettings")
+  if lsp_settings_status_ok then
+    lsp_settings.setup(opts)
   end
+end
 
-  if lsp.provider ~= nil and lsp.provider ~= "" then
-    local lspconfig = require "lspconfig"
+function M.get_common_opts()
+  return {
+    on_attach = M.common_on_attach,
+    on_init = M.common_on_init,
+    capabilities = M.common_capabilities(),
+  }
+end
 
-    if not lsp.setup.on_attach then
-      lsp.setup.on_attach = M.common_on_attach
-    end
-    if not lsp.setup.on_init then
-      lsp.setup.on_init = M.common_on_init
-    end
-    if not lsp.setup.capabilities then
-      lsp.setup.capabilities = M.common_capabilities()
-    end
+function M.setup()
+  Log:debug "Setting up LSP support"
 
-    lspconfig[lsp.provider].setup(lsp.setup)
+  local lsp_status_ok, _ = pcall(require, "lspconfig")
+  if not lsp_status_ok then
+    return
   end
-end
-
-function M.global_setup()
-  vim.lsp.protocol.CompletionItemKind = lvim.lsp.completion.item_kind
 
   for _, sign in ipairs(lvim.lsp.diagnostics.signs.values) do
     vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = sign.name })
   end
-
   require("lsp.handlers").setup()
 
-  local null_status_ok, null_ls = pcall(require, "null-ls")
-  if null_status_ok then
-    null_ls.config()
-    require("lspconfig")["null-ls"].setup(lvim.lsp.null_ls.setup)
+  if not utils.is_directory(lvim.lsp.templates_dir) then
+    require("lsp.templates").generate_templates()
   end
 
-  local utils = require "utils"
+  bootstrap_nlsp { config_home = utils.join_paths(get_config_dir(), "lsp-settings") }
 
-  local lsp_settings_status_ok, lsp_settings = pcall(require, "nlspsettings")
-  if lsp_settings_status_ok then
-    lsp_settings.setup {
-      config_home = utils.join_paths(get_config_dir(), "lsp-settings"),
-    }
-  end
+  require("lsp.null-ls").setup()
+
+  require("utils").toggle_autoformat()
 end
 
 return M

+ 0 - 31
lua/lsp/kind.lua

@@ -1,31 +0,0 @@
-local M = {}
-
-M.icons = {
-  Class = " ",
-  Color = " ",
-  Constant = "ﲀ ",
-  Constructor = " ",
-  Enum = "練",
-  EnumMember = " ",
-  Event = " ",
-  Field = " ",
-  File = "",
-  Folder = " ",
-  Function = " ",
-  Interface = "ﰮ ",
-  Keyword = " ",
-  Method = " ",
-  Module = " ",
-  Operator = "",
-  Property = " ",
-  Reference = " ",
-  Snippet = " ",
-  Struct = " ",
-  Text = " ",
-  TypeParameter = " ",
-  Unit = "塞",
-  Value = " ",
-  Variable = " ",
-}
-
-return M

+ 82 - 0
lua/lsp/manager.lua

@@ -0,0 +1,82 @@
+local M = {}
+
+local Log = require "core.log"
+local lsp_utils = require "lsp.utils"
+
+function M.init_defaults(languages)
+  for _, entry in ipairs(languages) do
+    if not lvim.lang[entry] then
+      lvim.lang[entry] = {
+        formatters = {},
+        linters = {},
+      }
+    end
+  end
+end
+
+local function is_overridden(server)
+  local overrides = lvim.lsp.override
+  if type(overrides) == "table" then
+    if vim.tbl_contains(overrides, server) then
+      return
+    end
+  end
+end
+
+function M.setup_server(server_name)
+  vim.validate {
+    name = { server_name, "string" },
+  }
+
+  if lsp_utils.is_client_active(server_name) or is_overridden(server_name) then
+    return
+  end
+
+  local lsp_installer_servers = require "nvim-lsp-installer.servers"
+  local server_available, requested_server = lsp_installer_servers.get_server(server_name)
+  if server_available then
+    if not requested_server:is_installed() then
+      Log:debug(string.format("[%s] is not installed", server_name))
+      if lvim.lsp.automatic_servers_installation then
+        Log:debug(string.format("Installing [%s]", server_name))
+        requested_server:install()
+      else
+        return
+      end
+    end
+  end
+
+  local default_config = {
+    on_attach = require("lsp").common_on_attach,
+    on_init = require("lsp").common_on_init,
+    capabilities = require("lsp").common_capabilities(),
+  }
+
+  local status_ok, custom_config = pcall(require, "lsp/providers/" .. requested_server.name)
+  if status_ok then
+    local new_config = vim.tbl_deep_extend("force", default_config, custom_config)
+    Log:debug("Using custom configuration for requested server: " .. requested_server.name)
+    requested_server:setup(new_config)
+  else
+    Log:debug("Using the default configuration for requested server: " .. requested_server.name)
+    requested_server:setup(default_config)
+  end
+end
+
+function M.setup(servers)
+  local status_ok, _ = pcall(require, "nvim-lsp-installer")
+  if not status_ok then
+    return
+  end
+
+  --- allow using a single value
+  if type(servers) == "string" then
+    servers = { servers }
+  end
+
+  for _, server in ipairs(servers) do
+    M.setup_server(server)
+  end
+end
+
+return M

+ 8 - 22
lua/lsp/null-ls/formatters.lua

@@ -1,29 +1,14 @@
 local M = {}
-local formatters_by_ft = {}
 
 local null_ls = require "null-ls"
 local services = require "lsp.null-ls.services"
 local Log = require "core.log"
 
-local function list_names(formatters, options)
-  options = options or {}
-  local filter = options.filter or "supported"
-
-  return vim.tbl_keys(formatters[filter])
-end
-
 function M.list_supported_names(filetype)
-  if not formatters_by_ft[filetype] then
-    return {}
-  end
-  return list_names(formatters_by_ft[filetype], { filter = "supported" })
-end
-
-function M.list_unsupported_names(filetype)
-  if not formatters_by_ft[filetype] then
-    return {}
-  end
-  return list_names(formatters_by_ft[filetype], { filter = "unsupported" })
+  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)
@@ -62,12 +47,13 @@ function M.list_configured(formatter_configs)
   return { supported = formatters, unsupported = errors }
 end
 
-function M.setup(filetype, options)
-  if not lvim.lang[filetype] or (formatters_by_ft[filetype] and not options.force_reload) then
+function M.setup(formatter_configs, filetype)
+  if vim.tbl_isempty(formatter_configs) then
     return
   end
 
-  formatters_by_ft[filetype] = M.list_configured(lvim.lang[filetype].formatters)
+  local formatters_by_ft = {}
+  formatters_by_ft[filetype] = M.list_configured(formatter_configs)
   null_ls.register { sources = formatters_by_ft[filetype].supported }
 end
 

+ 18 - 36
lua/lsp/null-ls/init.lua

@@ -1,44 +1,26 @@
 local M = {}
 
-function M.list_supported_provider_names(filetype)
-  local names = {}
-
-  local formatters = require "lsp.null-ls.formatters"
-  local linters = require "lsp.null-ls.linters"
-
-  vim.list_extend(names, formatters.list_supported_names(filetype))
-  vim.list_extend(names, linters.list_supported_names(filetype))
-
-  return names
-end
-
-function M.list_unsupported_provider_names(filetype)
-  local names = {}
-
-  local formatters = require "lsp.null-ls.formatters"
-  local linters = require "lsp.null-ls.linters"
-
-  vim.list_extend(names, formatters.list_unsupported_names(filetype))
-  vim.list_extend(names, linters.list_unsupported_names(filetype))
-
-  return names
-end
-
--- TODO: for linters and formatters with spaces and '-' replace with '_'
-function M.setup(filetype, options)
-  options = options or {}
-
-  local ok, _ = pcall(require, "null-ls")
-  if not ok then
-    require("core.log"):error "Missing null-ls dependency"
+local Log = require "core.log"
+local formatters = require "lsp.null-ls.formatters"
+local linters = require "lsp.null-ls.linters"
+
+function M:setup()
+  local status_ok, null_ls = pcall(require, "null-ls")
+  if not status_ok then
+    Log:error "Missing null-ls dependency"
     return
   end
 
-  local formatters = require "lsp.null-ls.formatters"
-  local linters = require "lsp.null-ls.linters"
-
-  formatters.setup(filetype, options)
-  linters.setup(filetype, options)
+  null_ls.config()
+  require("lspconfig")["null-ls"].setup {}
+  for _, filetype in pairs(lvim.lang) do
+    if filetype.formatters then
+      formatters.setup(filetype.formatters, filetype)
+    end
+    if filetype.linters then
+      linters.setup(filetype.linters, filetype)
+    end
+  end
 end
 
 return M

+ 8 - 22
lua/lsp/null-ls/linters.lua

@@ -1,29 +1,14 @@
 local M = {}
-local linters_by_ft = {}
 
 local null_ls = require "null-ls"
 local services = require "lsp.null-ls.services"
 local Log = require "core.log"
 
-local function list_names(linters, options)
-  options = options or {}
-  local filter = options.filter or "supported"
-
-  return vim.tbl_keys(linters[filter])
-end
-
 function M.list_supported_names(filetype)
-  if not linters_by_ft[filetype] then
-    return {}
-  end
-  return list_names(linters_by_ft[filetype], { filter = "supported" })
-end
-
-function M.list_unsupported_names(filetype)
-  if not linters_by_ft[filetype] then
-    return {}
-  end
-  return list_names(linters_by_ft[filetype], { filter = "unsupported" })
+  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)
@@ -62,12 +47,13 @@ function M.list_configured(linter_configs)
   return { supported = linters, unsupported = errors }
 end
 
-function M.setup(filetype, options)
-  if not lvim.lang[filetype] or (linters_by_ft[filetype] and not options.force_reload) then
+function M.setup(linter_configs, filetype)
+  if vim.tbl_isempty(linter_configs) then
     return
   end
 
-  linters_by_ft[filetype] = M.list_configured(lvim.lang[filetype].linters)
+  local linters_by_ft = {}
+  linters_by_ft[filetype] = M.list_configured(linter_configs)
   null_ls.register { sources = linters_by_ft[filetype].supported }
 end
 

+ 15 - 0
lua/lsp/null-ls/services.lua

@@ -45,4 +45,19 @@ function M.find_command(command)
   return nil
 end
 
+function M.list_registered_providers_names(filetype)
+  local u = require "null-ls.utils"
+  local c = require "null-ls.config"
+  local registered = {}
+  for method, source in pairs(c.get()._methods) do
+    for name, filetypes in pairs(source) do
+      if u.filetype_matches(filetypes, filetype) then
+        registered[method] = registered[method] or {}
+        table.insert(registered[method], name)
+      end
+    end
+  end
+  return registered
+end
+
 return M

+ 30 - 0
lua/lsp/providers/jsonls.lua

@@ -0,0 +1,30 @@
+local schemas = nil
+local status_ok, jsonls_settings = pcall(require, "nlspsettings.jsonls")
+if status_ok then
+  schemas = jsonls_settings.get_default_schemas()
+end
+
+local opts = {
+  setup = {
+    settings = {
+      json = {
+        schemas = schemas,
+        --   = {
+        --   {
+        --     fileMatch = { "package.json" },
+        --     url = "https://json.schemastore.org/package.json",
+        --   },
+        -- },
+      },
+    },
+    commands = {
+      Format = {
+        function()
+          vim.lsp.buf.range_formatting({}, { 0, 0 }, { vim.fn.line "$", 0 })
+        end,
+      },
+    },
+  },
+}
+
+return opts

+ 19 - 0
lua/lsp/providers/sumneko_lua.lua

@@ -0,0 +1,19 @@
+local opts = {
+  settings = {
+    Lua = {
+      diagnostics = {
+        globals = { "vim", "lvim" },
+      },
+      workspace = {
+        library = {
+          [require("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,
+      },
+    },
+  },
+}
+return opts

+ 26 - 0
lua/lsp/providers/vuels.lua

@@ -0,0 +1,26 @@
+local opts = {
+  setup = {
+    root_dir = function(fname)
+      local util = require "lspconfig/util"
+      return util.root_pattern "package.json"(fname) or util.root_pattern "vue.config.js"(fname) or vim.fn.getcwd()
+    end,
+    init_options = {
+      config = {
+        vetur = {
+          completion = {
+            autoImport = true,
+            tagCasing = "kebab",
+            useScaffoldSnippets = true,
+          },
+          useWorkspaceDependencies = true,
+          validation = {
+            script = true,
+            style = true,
+            template = true,
+          },
+        },
+      },
+    },
+  },
+}
+return opts

+ 98 - 0
lua/lsp/templates.lua

@@ -0,0 +1,98 @@
+local M = {}
+
+local Log = require "core.log"
+local utils = require "utils"
+local get_supported_filetypes = require("lsp.utils").get_supported_filetypes
+
+local ftplugin_dir = lvim.lsp.templates_dir
+
+local join_paths = _G.join_paths
+
+function M.remove_template_files()
+  -- remove any outdated files
+  for _, file in ipairs(vim.fn.glob(ftplugin_dir .. "/*.lua", 1, 1)) do
+    vim.fn.delete(file)
+  end
+end
+
+---Checks if a server is ignored by default because of a conflict
+---Only TSServer is enabled by default for the javascript-family
+---@param server_name string
+function M.is_ignored(server_name, filetypes)
+  --TODO: this is easy to be made configurable once stable
+  filetypes = filetypes or get_supported_filetypes(server_name)
+
+  if vim.tbl_contains(filetypes, "javascript") then
+    if server_name == "tsserver" or server_name == "tailwindcss" then
+      return false
+    else
+      return true
+    end
+  end
+
+  local blacklist = {
+    "jedi_language_server",
+    "pylsp",
+    "sqlls",
+    "sqls",
+    "angularls",
+    "ansiblels",
+  }
+  return vim.tbl_contains(blacklist, server_name)
+end
+
+---Generates an ftplugin file based on the server_name in the selected directory
+---@param server_name string name of a valid language server, e.g. pyright, gopls, tsserver, etc.
+---@param dir string the full path to the desired directory
+function M.generate_ftplugin(server_name, dir)
+  -- we need to go through lspconfig to get the corresponding filetypes currently
+  local filetypes = get_supported_filetypes(server_name) or {}
+  if not filetypes then
+    return
+  end
+
+  if M.is_ignored(server_name, filetypes) then
+    return
+  end
+
+  -- print("got associated filetypes: " .. vim.inspect(filetypes))
+
+  for _, filetype in ipairs(filetypes) do
+    local filename = join_paths(dir, filetype .. ".lua")
+    local setup_cmd = string.format([[require("lsp.manager").setup(%q)]], server_name)
+    -- print("using setup_cmd: " .. setup_cmd)
+    -- overwrite the file completely
+    utils.write_file(filename, setup_cmd .. "\n", "a")
+  end
+end
+
+---Generates ftplugin files based on a list of server_names
+---The files are generated to a runtimepath: "$LUNARVIM_RUNTIME_DIR/site/after/ftplugin/template.lua"
+---@param servers_names table list of servers to be enabled. Will add all by default
+function M.generate_templates(servers_names)
+  servers_names = servers_names or {}
+
+  Log:debug "Templates installation in progress"
+
+  M.remove_template_files()
+
+  if vim.tbl_isempty(servers_names) then
+    local available_servers = require("nvim-lsp-installer.servers").get_available_servers()
+
+    for _, server in pairs(available_servers) do
+      table.insert(servers_names, server.name)
+    end
+  end
+
+  -- create the directory if it didn't exist
+  if not utils.is_directory(lvim.lsp.templates_dir) then
+    vim.fn.mkdir(ftplugin_dir, "p")
+  end
+
+  for _, server in ipairs(servers_names) do
+    M.generate_ftplugin(server, ftplugin_dir)
+  end
+  Log:debug "Templates installation is complete"
+end
+
+return M

+ 49 - 8
lua/lsp/utils.lua

@@ -10,19 +10,60 @@ function M.is_client_active(name)
   return false
 end
 
--- FIXME: this should return a list instead
-function M.get_active_client_by_ft(filetype)
-  if not lvim.lang[filetype] or not lvim.lang[filetype].lsp then
-    return nil
-  end
+function M.disable_formatting_capability(client)
+  -- FIXME: figure out a reasonable way to do this
+  client.resolved_capabilities.document_formatting = false
+  require("core.log"):debug(string.format("Turning off formatting capability for language server [%s] ", client.name))
+end
 
+function M.get_active_client_by_ft(filetype)
+  local matches = {}
   local clients = vim.lsp.get_active_clients()
   for _, client in pairs(clients) do
-    if client.name == lvim.lang[filetype].lsp.provider then
-      return client
+    local supported_filetypes = client.config.filetypes or {}
+    if client.name ~= "null-ls" and vim.tbl_contains(supported_filetypes, filetype) then
+      table.insert(matches, client)
+    end
+  end
+  return matches
+end
+
+function M.get_ls_capabilities(client_id)
+  if not client_id then
+    local buf_clients = vim.lsp.buf_get_clients()
+    for _, buf_client in ipairs(buf_clients) do
+      if buf_client.name ~= "null-ls" then
+        client_id = buf_client.id
+        break
+      end
+    end
+  end
+  if not client_id then
+    error "Unable to determine client_id"
+    return
+  end
+
+  local client = vim.lsp.get_client_by_id(tonumber(client_id))
+
+  local enabled_caps = {}
+  for capability, status in pairs(client.resolved_capabilities) do
+    if status == true then
+      table.insert(enabled_caps, capability)
+    end
+  end
+
+  return enabled_caps
+end
+
+function M.get_supported_filetypes(server_name)
+  -- print("got filetypes query request for: " .. server_name)
+  local configs = require "lspconfig/configs"
+  pcall(require, ("lspconfig/" .. server_name))
+  for _, config in pairs(configs) do
+    if config.name == server_name then
+      return config.document_config.default_config.filetypes or {}
     end
   end
-  return nil
 end
 
 return M

+ 1 - 6
lua/plugins.lua

@@ -6,12 +6,7 @@ return {
   { "jose-elias-alvarez/null-ls.nvim" },
   { "antoinemadec/FixCursorHold.nvim" }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open
   {
-    "kabouzeid/nvim-lspinstall",
-    event = "VimEnter",
-    config = function()
-      local lspinstall = require "core.lspinstall"
-      lspinstall.setup()
-    end,
+    "williamboman/nvim-lsp-installer",
   },
 
   { "nvim-lua/popup.nvim" },

+ 95 - 5
lua/utils/init.lua

@@ -99,8 +99,7 @@ function utils.reload_lv_config()
   vim.cmd ":PackerInstall"
   vim.cmd ":PackerCompile"
   -- vim.cmd ":PackerClean"
-  local null_ls = require "lsp.null-ls"
-  null_ls.setup(vim.bo.filetype, { force_reload = true })
+  require("lsp").setup()
   Log:info "Reloaded configuration"
 end
 
@@ -133,15 +132,106 @@ function utils.apply_defaults(config, default_config)
 end
 
 --- Checks whether a given path exists and is a file.
---@param filename (string) path to check
+--@param path (string) path to check
 --@returns (bool)
-function utils.is_file(filename)
-  local stat = uv.fs_stat(filename)
+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
+
+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
+
 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("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
+
 return utils
 
 -- TODO: find a new home for these autocommands

+ 0 - 13
tests/bootstrap_spec.lua

@@ -25,17 +25,4 @@ a.describe("initial start", function()
   a.it("should be able to run treesitter without errors", function()
     assert.truthy(vim.treesitter.highlighter.active)
   end)
-
-  a.it("should be able to load default packages without errors", function()
-    -- TODO: maybe there's a way to avoid hard-coding the names of the modules?
-    local startup_plugins = {
-      "packer",
-      "lspconfig",
-      "nlspsettings",
-      "null-ls",
-    }
-    for _, plugin in pairs(startup_plugins) do
-      assert.truthy(package.loaded[tostring(plugin)])
-    end
-  end)
 end)

+ 98 - 0
tests/lsp_spec.lua

@@ -0,0 +1,98 @@
+local a = require "plenary.async_lib.tests"
+local utils = require "utils"
+lvim.lsp.templates_dir = join_paths(get_runtime_dir(), "lvim", "tests", "artifacts")
+
+a.describe("lsp workflow", function()
+  local Log = require "core.log"
+  local logfile = Log:get_path()
+
+  a.it("shoud be able to delete ftplugin templates", function()
+    if utils.is_directory(lvim.lsp.templates_dir) then
+      assert.equal(vim.fn.delete(lvim.lsp.templates_dir, "rf"), 0)
+    end
+    assert.False(utils.is_directory(lvim.lsp.templates_dir))
+  end)
+
+  a.it("shoud be able to generate ftplugin templates", function()
+    if utils.is_directory(lvim.lsp.templates_dir) then
+      assert.equal(vim.fn.delete(lvim.lsp.templates_dir, "rf"), 0)
+    end
+    require("lsp").setup()
+
+    -- we need to delay this check until the generation is completed
+    vim.schedule(function()
+      assert.True(utils.is_directory(lvim.lsp.templates_dir))
+    end)
+  end)
+
+  a.it("shoud not attempt to re-generate ftplugin templates", function()
+    lvim.log.level = "debug"
+
+    local plugins = require "plugins"
+    require("plugin-loader"):load { plugins, lvim.plugins }
+
+    if utils.is_file(logfile) then
+      assert.equal(vim.fn.delete(logfile), 0)
+    end
+
+    assert.True(utils.is_directory(lvim.lsp.templates_dir))
+    require("lsp").setup()
+
+    -- we need to delay this check until the log gets populated
+    vim.schedule(function()
+      assert.False(utils.log_contains "templates")
+    end)
+  end)
+
+  a.it("shoud retrieve supported filetypes correctly", function()
+    local ocaml = {
+      name = "ocamlls",
+      filetypes = { "ocaml", "reason" },
+    }
+    local ocaml_fts = require("lsp.utils").get_supported_filetypes(ocaml.name)
+    assert.True(vim.deep_equal(ocaml.filetypes, ocaml_fts))
+
+    local tsserver = {
+      name = "tsserver",
+      filetypes = {
+        "javascript",
+        "javascriptreact",
+        "javascript.jsx",
+        "typescript",
+        "typescriptreact",
+        "typescript.tsx",
+      },
+    }
+    local tsserver_fts = require("lsp.utils").get_supported_filetypes(tsserver.name)
+    assert.True(vim.deep_equal(tsserver.filetypes, tsserver_fts))
+  end)
+
+  a.it("shoud ignore all javascript servers except tsserver and tailwindcss when generating templates", function()
+    local test_server = { name = "denols", filetypes = {} }
+    test_server.filetypes = require("lsp.utils").get_supported_filetypes(test_server.name)
+
+    assert.True(vim.tbl_contains(test_server.filetypes, "javascript"))
+
+    local is_ignored = require("lsp.templates").is_ignored(test_server.name)
+    assert.True(is_ignored)
+
+    local ts_template = utils.join_paths(lvim.lsp.templates_dir, "typescript.lua")
+
+    assert.True(utils.file_contains(ts_template, "tsserver"))
+    assert.True(utils.file_contains(ts_template, "tailwindcss"))
+    assert.False(utils.file_contains(ts_template, test_server.name))
+  end)
+
+  a.it("shoud not include blacklisted servers in the generated templates", function()
+    assert.True(utils.is_directory(lvim.lsp.templates_dir))
+    require("lsp").setup()
+
+    local blacklisted = { "jedi_language_server", "pylsp", "sqlls", "sqls", "angularls", "ansiblels" }
+
+    for _, file in ipairs(vim.fn.glob(lvim.lsp.templates_dir .. "/*.lua", 1, 1)) do
+      for _, server in ipairs(blacklisted) do
+        assert.False(utils.file_contains(file, server))
+      end
+    end
+  end)
+end)

+ 9 - 0
tests/minimal_init.lua

@@ -0,0 +1,9 @@
+local path_sep = vim.loop.os_uname().version:match "Windows" and "\\" or "/"
+
+vim.opt.rtp:append(os.getenv "LUNARVIM_RUNTIME_DIR" .. path_sep .. "lvim")
+
+require("bootstrap"):init()
+
+local config = require "config"
+-- config:init()
+config:load()

+ 34 - 0
tests/plugins_load_spec.lua

@@ -0,0 +1,34 @@
+local a = require "plenary.async_lib.tests"
+
+a.describe("plugin-loader", function()
+  a.it("should be able to load default packages without errors", function()
+    local plugins = require "plugins"
+    require("plugin-loader"):load { plugins, lvim.plugins }
+
+    -- TODO: maybe there's a way to avoid hard-coding the names of the modules?
+    local startup_plugins = {
+      "packer",
+    }
+
+    for _, plugin in ipairs(startup_plugins) do
+      assert.truthy(package.loaded[plugin])
+    end
+  end)
+
+  a.it("should be able to load lsp packages without errors", function()
+    local plugins = require "plugins"
+    require("plugin-loader"):load { plugins, lvim.plugins }
+
+    require("lsp").setup()
+
+    local lsp_packages = {
+      "lspconfig",
+      "nlspsettings",
+      "null-ls",
+    }
+
+    for _, plugin in ipairs(lsp_packages) do
+      assert.truthy(package.loaded[plugin])
+    end
+  end)
+end)

+ 9 - 0
utils/bin/lvim.ps1

@@ -0,0 +1,9 @@
+$env:XDG_DATA_HOME = ($env:XDG_DATA_HOME, "$env:APPDATA", 1 -ne $null)[0]
+$env:XDG_CONFIG_HOME = ($env:XDG_CONFIG_HOME, "$LOCALAPPDATA", 1 -ne $null)[0]
+$env:XDG_CACHE_HOME = ($env:XDG_CACHE_HOME, "$TEMP", 1 -ne $null)[0]
+
+$env:LUNARVIM_RUNTIME_DIR = ($env:LUNARVIM_RUNTIME_DIR, "$env:XDG_DATA_HOME\lunarvim", 1 -ne $null)[0]
+$env:LUNARVIM_CONFIG_DIR = ($env:LUNARVIM_CONFIG_DIR, "$env:XDG_CONFIG_HOME\lvim", 1 -ne $null)[0]
+$env:LUNARVIM_CACHE_DIR = ($env:LUNARVIM_CACHE_DIR, "$env:XDG_CACHE_HOME\lvim", 1 -ne $null)[0]
+
+nvim -u "$env:LUNARVIM_RUNTIME_DIR\lvim\init.lua"

+ 2 - 2
utils/bin/test_runner.sh

@@ -10,11 +10,11 @@ rm -f "$LUNARVIM_CONFIG_DIR/plugin/packer_compiled.lua"
 
 lvim() {
   # TODO: allow running with a minimal_init.lua
-  nvim -u "$LUNARVIM_RUNTIME_DIR/lvim/init.lua" --cmd "set runtimepath+=$LUNARVIM_RUNTIME_DIR/lvim" "$@"
+  nvim -u "$LUNARVIM_RUNTIME_DIR/lvim/tests/minimal_init.lua" --cmd "set runtimepath+=$LUNARVIM_RUNTIME_DIR/lvim" "$@"
 }
 
 if [ -n "$1" ]; then
   lvim --headless -c "lua require('plenary.busted').run('$1')"
 else
-  lvim --headless -c "PlenaryBustedDirectory tests/ { minimal_init = './init.lua' }"
+  lvim --headless -c "PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal_init.lua' }"
 fi

+ 14 - 1
utils/installer/config.example.lua

@@ -55,7 +55,20 @@ lvim.builtin.nvimtree.setup.view.side = "left"
 lvim.builtin.nvimtree.show_icons.git = 0
 
 -- if you don't want all the parsers change this to a table of the ones you want
-lvim.builtin.treesitter.ensure_installed = "maintained"
+lvim.builtin.treesitter.ensure_installed = {
+  "bash",
+  "c",
+  "javascript",
+  "json",
+  "lua",
+  "python",
+  "typescript",
+  "css",
+  "rust",
+  "java",
+  "yaml",
+}
+
 lvim.builtin.treesitter.ignore_install = { "haskell" }
 lvim.builtin.treesitter.highlight.enabled = true
 

+ 280 - 0
utils/installer/install.ps1

@@ -0,0 +1,280 @@
+$ErrorActionPreference = "Stop" # exit when command fails
+
+# set script variables
+# FIXME: temporarily set the branch to the new one
+$LV_BRANCH = ($LV_BRANCH, "lang-refactor", 1 -ne $null)[0]
+$LV_REMOTE = ($LV_REMOTE, "lunarvim/lunarvim.git", 1 -ne $null)[0]
+$INSTALL_PREFIX = ($INSTALL_PREFIX, "$HOME\.local", 1 -ne $null)[0]
+
+$env:XDG_DATA_HOME = ($env:XDG_DATA_HOME, "$env:APPDATA", 1 -ne $null)[0]
+$env:XDG_CONFIG_HOME = ($env:XDG_CONFIG_HOME, "$LOCALAPPDATA", 1 -ne $null)[0]
+$env:XDG_CACHE_HOME = ($env:XDG_CACHE_HOME, "$TEMP", 1 -ne $null)[0]
+$env:LUNARVIM_RUNTIME_DIR = ($env:LUNARVIM_RUNTIME_DIR, "$env:XDG_DATA_HOME\lunarvim", 1 -ne $null)[0]
+$env:LUNARVIM_CONFIG_DIR = ($env:LUNARVIM_CONFIG_DIR, "$env:XDG_CONFIG_HOME\lvim", 1 -ne $null)[0]
+$env:LUNARVIM_CACHE_DIR = ($env:LUNARVIM_CACHE_DIR, "$env:XDG_CACHE_HOME\lvim", 1 -ne $null)[0]
+
+
+$__lvim_dirs = (
+    "$env:LUNARVIM_CONFIG_DIR",
+    "$env:LUNARVIM_RUNTIME_DIR",
+    "$env:LUNARVIM_CACHE_DIR"
+)
+
+function main($cliargs) {
+    Write-Output "  
+
+		88\                                                   88\               
+		88 |                                                  \__|              
+		88 |88\   88\ 888888$\   888888\   888888\ 88\    88\ 88\ 888888\8888\  
+		88 |88 |  88 |88  __88\  \____88\ 88  __88\\88\  88  |88 |88  _88  _88\ 
+		88 |88 |  88 |88 |  88 | 888888$ |88 |  \__|\88\88  / 88 |88 / 88 / 88 |
+		88 |88 |  88 |88 |  88 |88  __88 |88 |       \88$  /  88 |88 | 88 | 88 |
+		88 |\888888  |88 |  88 |\888888$ |88 |        \$  /   88 |88 | 88 | 88 |
+		\__| \______/ \__|  \__| \_______|\__|         \_/    \__|\__| \__| \__|
+  
+  "
+  
+    __add_separator "80"
+  
+    # skip this in a Github workflow
+    if ( $null -eq "$GITHUB_ACTIONS" ) {
+        install_packer
+        setup_shim
+        exit
+    }
+
+    __add_separator "80"
+
+    check_system_deps
+
+    Write-Output "Would you like to check lunarvim's NodeJS dependencies?"
+    $answer = Read-Host "[y]es or [n]o (default: no) "
+    if ("$answer" -eq "y" -or "$answer" -eq "Y") {
+        install_nodejs_deps
+    } 
+
+    Write-Output "Would you like to check lunarvim's Python dependencies?"
+    $answer = Read-Host "[y]es or [n]o (default: no) "
+    if ("$answer" -eq "y" -or "$answer" -eq "Y") {
+        install_python_deps
+    } 
+
+    __add_separator "80"
+
+    Write-Output "Backing up old LunarVim configuration"
+    backup_old_config
+
+    __add_separator "80" 
+  
+    if ($cliargs.Contains("--overwrite")) {
+        Write-Output "!!Warning!! -> Removing all lunarvim related config because of the --overwrite flag"
+        $answer = Read-Host "Would you like to continue? [y]es or [n]o "
+        if ("$answer" -ne "y" -and "$answer" -ne "Y") {
+            exit 1
+        } 
+		
+        foreach ($dir in $__lvim_dirs) {
+            if (Test-Path "$dir") {
+                Remove-Item -Force -Recurse "$dir"
+            }
+        }
+    }
+  
+    if (Test-Path "$env:LUNARVIM_RUNTIME_DIR\site\pack\packer\start\packer.nvim") {
+        Write-Output "Packer already installed"
+    }
+    else {
+        install_packer
+    }
+  
+    __add_separator "80"
+  
+    if (Test-Path "$env:LUNARVIM_RUNTIME_DIR\lvim\init.lua" ) {
+        Write-Output "Updating LunarVim"
+        update_lvim
+    }
+    else {
+        if ($cliargs.Contains("--testing")) {
+            copy_local_lvim_repository
+        }
+        else {
+            clone_lvim
+        }
+        setup_lvim
+    }
+  
+    __add_separator "80"
+}
+
+function print_missing_dep_msg($dep) {
+    Write-Output "[ERROR]: Unable to find dependency [$dep]"
+    Write-Output "Please install it first and re-run the installer. Try: $RECOMMEND_INSTALL $dep"
+}
+
+function install_system_package($dep) {
+    if (Get-Command -Name "winget" -ErrorAction SilentlyContinue) {
+        Write-Output "[INFO]: Attempting to install dependency [$dep] with winget"
+        $install_cmd = "winget install --interactive"
+    }
+    elseif (Get-Command -Name "scoop" -ErrorAction SilentlyContinue) {
+        Write-Output "[INFO]: Attempting to install dependency [$dep] with scoop"
+        # TODO: check if it's fine to not run it with --global
+        $install_cmd = "scoop install"
+    }
+    else {
+        print_missing_dep_msg "$dep"
+        exit 1
+    }
+
+    try {
+        Invoke-Command $install_cmd $dep -ErrorAction Stop
+    }
+    catch {
+        print_missing_dep_msg "$dep"
+        exit 1
+    }
+}
+
+function check_system_dep($dep) {
+    try { 
+        Get-Command -Name $dep -ErrorAction Stop | Out-Null 
+    }
+    catch { 
+        install_system_package "$dep"
+    }
+}
+
+function check_system_deps() {
+    Write-Output "[INFO]: Checking dependencies.."
+    check_system_dep "git"
+    check_system_dep "nvim"
+	
+}
+
+function install_nodejs_deps() {
+    try {
+        check_system_dep "node"
+        Invoke-Command npm install -g neovim tree-sitter-cli  -ErrorAction Break
+    }
+    catch {
+        print_missing_dep_msg "$dep"
+    }
+}
+
+function install_python_deps() {
+    try {
+        check_system_dep "pip"
+        Invoke-Command python -m pip install --user pynvim -ErrorAction Break
+    }
+    catch {
+        print_missing_dep_msg "$dep"
+    }
+}
+
+function backup_old_config() {
+    foreach ($dir in $__lvim_dirs) {
+        # we create an empty folder for subsequent commands \
+        # that require an existing directory	 
+        if ( Test-Path "$dir") {
+            New-Item "$dir.bak" -ItemType Directory -Force
+            Copy-Item -Recurse "$dir\*" "$dir.bak\."
+        }
+    }
+
+    Write-Output "Backup operation complete"
+}
+
+
+function install_packer() {
+    Invoke-Command -ErrorAction Stop -ScriptBlock { git clone --progress --depth 1 "https://github.com/wbthomason/packer.nvim" "$env:LUNARVIM_RUNTIME_DIR\site\pack\packer\start\packer.nvim" }
+}
+  
+function copy_local_lvim_repository() {
+    Write-Output "Copy local LunarVim configuration"
+    Copy-Item -Path "$((Get-Item $PWD).Parent.Parent.FullName)" -Destination "$env:LUNARVIM_RUNTIME_DIR/lvim" -Recurse
+}
+
+function clone_lvim() {
+    Write-Output "Cloning LunarVim configuration"
+    try {
+        Invoke-Command -ErrorAction Stop -ScriptBlock { git clone --progress --branch "$LV_BRANCH" --depth 1 "https://github.com/$LV_REMOTE" "$env:LUNARVIM_RUNTIME_DIR/lvim" } 
+    }
+    catch {
+        Write-Output "Failed to clone repository. Installation failed."
+        exit 1		
+    }
+}
+
+function setup_shim() {
+    if ((Test-Path "$INSTALL_PREFIX\bin") -eq $false) {
+        New-Item "$INSTALL_PREFIX\bin" -ItemType Directory
+    }
+    Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\bin\lvim.ps1" -Destination "$INSTALL_PREFIX\bin\lvim.ps1" -Force
+}
+
+function setup_lvim() {
+    Write-Output "Installing LunarVim shim"
+  
+    setup_shim
+  
+    Write-Output "Preparing Packer setup"
+
+    if ((Test-Path "$env:LUNARVIM_CONFIG_DIR") -eq $false) {
+        New-Item "$env:LUNARVIM_CONFIG_DIR" -ItemType Directory
+    }
+
+    Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\installer\config.example-no-ts.lua" `
+        "$env:LUNARVIM_CONFIG_DIR\config.lua"
+  
+	Write-Output "Packer setup complete"
+	
+	__add_separator "80"
+
+	Copy-Item "$env:LUNARVIM_RUNTIME_DIR\lvim\utils\installer\config.example.lua" "$env:LUNARVIM_CONFIG_DIR\config.lua"
+  
+	$answer = Read-Host $(`
+	"Would you like to create an alias inside your Powershell profile?`n" +`
+	"(This enables you to start lvim with the command 'lvim') [y]es or [n]o (default: no)" )
+	if ("$answer" -eq "y" -and "$answer" -eq "Y") {
+		create_alias
+	} 
+
+	__add_separator "80"
+
+    Write-Output "Thank you for installing LunarVim!!"
+    Write-Output "You can start it by running: $INSTALL_PREFIX\bin\lvim.ps1"
+    Write-Output "Do not forget to use a font with glyphs (icons) support [https://github.com/ryanoasis/nerd-fonts]"
+}
+
+
+function update_lvim() {
+    try {
+        Invoke-Command git -C "$env:LUNARVIM_RUNTIME_DIR/lvim" status -uno
+    }
+    catch {
+        git -C "$env:LUNARVIM_RUNTIME_DIR/lvim" pull --ff-only --progress -or
+        Write-Output "Unable to guarantee data integrity while updating. Please do that manually instead."
+        exit 1
+    }
+    Write-Output "Your LunarVim installation is now up to date!"
+}
+
+function __add_separator($div_width) {
+    "-" * $div_width
+    Write-Output ""
+}
+
+function create_alias {
+	if($null -eq $(Get-Alias | Select-String "lvim")){
+		Add-Content -Path $PROFILE -Value $(-join @('Set-Alias lvim "', "$INSTALL_PREFIX", '\bin\lvim.ps1"'))
+		
+		Write-Output ""
+		Write-Host 'To use the new alias in this window reload your profile with ". $PROFILE".' -ForegroundColor Yellow
+
+	}else {
+		Write-Output "Alias is already set and will not be reset."
+	}
+}
+
+main "$args"
+

+ 1 - 0
utils/installer/uninstall.ps1

@@ -0,0 +1 @@
+Remove-Item -Path "$HOME/.local/share/lunarvim" -Recurse -Force