diff options
28 files changed, 537 insertions, 207 deletions
| diff --git a/.github/workflows/format.yaml b/.github/workflows/format.yaml index a7f7d9f8..b63b89d7 100644 --- a/.github/workflows/format.yaml +++ b/.github/workflows/format.yaml @@ -4,6 +4,11 @@ on:    pull_request:      branches:        - "rolling" +    paths: +      - 'lua/**' +      - 'snapshots/**' +      - 'tests/**' +      - 'utils/**'  jobs:    stylua-check: diff --git a/.github/workflows/install.yaml b/.github/workflows/install.yaml index 4266896b..6e3685dd 100644 --- a/.github/workflows/install.yaml +++ b/.github/workflows/install.yaml @@ -5,6 +5,11 @@ on:      branches:        - "master"        - "rolling" +    paths: +      - 'lua/**' +      - 'snapshots/**' +      - 'tests/**' +      - 'utils/**'  jobs:    unixish: diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 9746425d..c238a5d1 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -4,6 +4,11 @@ on:    pull_request:      branches:        - "rolling" +    paths: +      - 'lua/**' +      - 'snapshots/**' +      - 'tests/**' +      - 'utils/**'  jobs:    lua-linter: diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml new file mode 100644 index 00000000..ba16ddca --- /dev/null +++ b/.github/workflows/plugins.yml @@ -0,0 +1,65 @@ +name: plugins-version-bump + +on: +  workflow_dispatch: +    inputs: +      logLevel: +        description: 'Log level' +        required: false +        default: 'warning' +        type: choice +        options: +        - info +        - warning +        - debug +  schedule: +    # note: this will keep updating the existing branch +    - cron: "*/15 10-14 * * 0,6" +    - cron: "0 14 * * 1-5" + +jobs: +  plugins-version-bump: +    runs-on: ubuntu-latest +    continue-on-error: true +    permissions: +      contents: write +      pull-requests: write +    steps: +      - uses: actions/checkout@v2 +        with: +          ref: ${{ github.head_ref }} + +      - name: Install neovim binary +        uses: rhysd/action-setup-vim@v1 +        with: +          neovim: true +          version: v0.6.1 + +      - name: Install LunarVim +        timeout-minutes: 4 +        run: | +          ./utils/installer/install.sh --local --no-install-dependencies + +      - name: run upgrade script +        run: make generate_new_lockfile + +      - name: Re-install LunarVim +        timeout-minutes: 4 +        run: | +          ./utils/installer/uninstall.sh --remove-backups +          ./utils/installer/install.sh --local --no-install-dependencies + +      - name: Run unit-tests +        # NOTE: make sure to adjust the timeout if you start adding a lot of tests +        timeout-minutes: 4 +        run: make test + +      - name: Create Pull Request +        uses: peter-evans/create-pull-request@v4 +        with: +          branch: plugins-bump +          delete-branch: true # Delete the branch when closing pull requests, and when undeleted after merging. +          token: ${{ secrets.GITHUB_TOKEN }} +          author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> +          title: "chore: bump plugins version" +          commit-message: "chore: bump plugins version" @@ -16,9 +16,9 @@ uninstall:  	@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.git").generate_plugins_sha("latest-sha.lua")' -c 'qall' +generate_new_lockfile: +	@echo generating core-plugins latest lockfile +	bash ./utils/ci/generate_new_lockfile.sh  lint: lint-lua lint-sh @@ -41,7 +41,9 @@ To run the install script without any interaction you can pass the `-y` flag to  The same way, you can use `--no-install-dependencies` to skip the dependency installation. -### Windows (Powershell): +### Windows (Powershell 7+): + +Powershell v7+ is required for this script. For instructions on how to install, [click here.](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2)  ```powershell  Invoke-WebRequest https://raw.githubusercontent.com/LunarVim/LunarVim/master/utils/installer/install.ps1 -UseBasicParsing | Invoke-Expression @@ -76,7 +78,7 @@ lvim.keys.normal_mode["<C-s>"] = ":w<cr>"  -- lvim.builtin.which_key.mappings["P"] = { "<cmd>Telescope projects<CR>", "Projects" }  -- Configure builtin plugins -lvim.builtin.dashboard.active = true +lvim.builtin.alpha.active = true  lvim.builtin.notify.active = true  lvim.builtin.terminal.active = true diff --git a/lua/lvim/config/init.lua b/lua/lvim/config/init.lua index c3fe0438..6927d52a 100644 --- a/lua/lvim/config/init.lua +++ b/lua/lvim/config/init.lua @@ -124,18 +124,20 @@ end  --- Override the configuration with a user provided one  -- @param config_path The path to the configuration overrides  function M:reload() -  require_clean("lvim.utils.hooks").run_pre_reload() +  vim.schedule(function() +    require_clean("lvim.utils.hooks").run_pre_reload() -  M:init() -  M:load() +    M:init() +    M:load() -  require("lvim.core.autocmds").configure_format_on_save() +    require("lvim.core.autocmds").configure_format_on_save() -  local plugins = require "lvim.plugins" -  local plugin_loader = require "lvim.plugin-loader" +    local plugins = require "lvim.plugins" +    local plugin_loader = require "lvim.plugin-loader" -  plugin_loader.load { plugins, lvim.plugins } -  require_clean("lvim.utils.hooks").run_post_reload() +    plugin_loader.reload { plugins, lvim.plugins } +    require_clean("lvim.utils.hooks").run_post_reload() +  end)  end  return M diff --git a/lua/lvim/core/info.lua b/lua/lvim/core/info.lua index 34a5a7dd..9c9652da 100644 --- a/lua/lvim/core/info.lua +++ b/lua/lvim/core/info.lua @@ -120,7 +120,7 @@ local function make_override_info(ft)  end  function M.toggle_popup(ft) -  local clients = vim.lsp.get_active_clients(ft) +  local clients = vim.lsp.get_active_clients()    local client_names = {}    local bufnr = vim.api.nvim_get_current_buf()    local ts_active_buffers = vim.tbl_keys(vim.treesitter.highlighter.active) @@ -161,24 +161,22 @@ function M.toggle_popup(ft)    local content_provider = function(popup)      local content = {} -    for _, section in -      ipairs { -        M.banner, -        { "" }, -        { "" }, -        header, -        { "" }, -        lsp_info, -        { "" }, -        override_info, -        { "" }, -        formatters_info, -        { "" }, -        linters_info, -        { "" }, -        code_actions_info, -      } -    do +    for _, section in ipairs { +      M.banner, +      { "" }, +      { "" }, +      header, +      { "" }, +      lsp_info, +      { "" }, +      override_info, +      { "" }, +      formatters_info, +      { "" }, +      linters_info, +      { "" }, +      code_actions_info, +    } do        vim.list_extend(content, section)      end diff --git a/lua/lvim/core/log.lua b/lua/lvim/core/log.lua index e5a6d5db..d0e74f18 100644 --- a/lua/lvim/core/log.lua +++ b/lua/lvim/core/log.lua @@ -19,6 +19,9 @@ function Log:init()      return nil    end +  package.loaded["packer.log"] = nil +  require("packer.log").new { level = lvim.log.level } +    local log_level = Log.levels[(lvim.log.level):upper() or "WARN"]    local lvim_log = {      lvim = { diff --git a/lua/lvim/core/telescope.lua b/lua/lvim/core/telescope.lua index 11a9655d..a4df4b3f 100644 --- a/lua/lvim/core/telescope.lua +++ b/lua/lvim/core/telescope.lua @@ -55,7 +55,7 @@ function M.config()            ["<C-j>"] = actions.cycle_history_next,            ["<C-k>"] = actions.cycle_history_prev,            ["<C-q>"] = actions.smart_send_to_qflist + actions.open_qflist, -          ["<CR>"] = actions.select_default + actions.center, +          ["<CR>"] = actions.select_default,          },          n = {            ["<C-n>"] = actions.move_selection_next, diff --git a/lua/lvim/lsp/config.lua b/lua/lvim/lsp/config.lua index ca6f66bb..3a345f15 100644 --- a/lua/lvim/lsp/config.lua +++ b/lua/lvim/lsp/config.lua @@ -78,7 +78,7 @@ return {      "graphql",      "jedi_language_server",      "ltex", -    "ocamllsp", +    "ocamlls",      "phpactor",      "psalm",      "pylsp", diff --git a/lua/lvim/lsp/providers/sumneko_lua.lua b/lua/lvim/lsp/providers/sumneko_lua.lua index 7c0030c1..fa0d2d31 100644 --- a/lua/lvim/lsp/providers/sumneko_lua.lua +++ b/lua/lvim/lsp/providers/sumneko_lua.lua @@ -2,7 +2,7 @@ local opts = {    settings = {      Lua = {        diagnostics = { -        globals = { "vim", "lvim" }, +        globals = { "vim", "lvim", "packer_plugins" },        },        workspace = {          library = { diff --git a/lua/lvim/plugin-loader.lua b/lua/lvim/plugin-loader.lua index 5208d5bf..e42be52e 100644 --- a/lua/lvim/plugin-loader.lua +++ b/lua/lvim/plugin-loader.lua @@ -1,41 +1,29 @@  local plugin_loader = {} -local in_headless = #vim.api.nvim_list_uis() == 0 -  local utils = require "lvim.utils"  local Log = require "lvim.core.log" +local join_paths = utils.join_paths +local in_headless = #vim.api.nvim_list_uis() == 0 +  -- we need to reuse this outside of init() -local compile_path = get_config_dir() .. "/plugin/packer_compiled.lua" +local compile_path = join_paths(get_config_dir(), "plugin", "packer_compiled.lua") +local snapshot_path = join_paths(get_cache_dir(), "snapshots") +local default_snapshot = join_paths(get_lvim_base_dir(), "snapshots", "default.json")  function plugin_loader.init(opts)    opts = opts or {} -  local install_path = opts.install_path or vim.fn.stdpath "data" .. "/site/pack/packer/start/packer.nvim" -  local package_root = opts.package_root or vim.fn.stdpath "data" .. "/site/pack" - -  if vim.fn.empty(vim.fn.glob(install_path)) > 0 then -    vim.fn.system { "git", "clone", "--depth", "1", "https://github.com/wbthomason/packer.nvim", install_path } -    vim.cmd "packadd packer.nvim" -  end - -  local log_level = in_headless and "debug" or "warn" -  if lvim.log and lvim.log.level then -    log_level = lvim.log.level -  end +  local install_path = opts.install_path +    or join_paths(vim.fn.stdpath "data", "site", "pack", "packer", "start", "packer.nvim") -  local _, packer = pcall(require, "packer") -  packer.init { -    package_root = package_root, +  local init_opts = { +    package_root = opts.package_root or join_paths(vim.fn.stdpath "data", "site", "pack"),      compile_path = compile_path, -    log = { level = log_level }, +    snapshot_path = snapshot_path, +    log = { level = "warn" },      git = {        clone_timeout = 300, -      subcommands = { -        -- this is more efficient than what Packer is using -        fetch = "fetch --no-tags --no-recurse-submodules --update-shallow --progress", -      },      }, -    max_jobs = 50,      display = {        open_fn = function()          return require("packer.util").float { border = "rounded" } @@ -43,8 +31,24 @@ function plugin_loader.init(opts)      },    } -  if not in_headless then -    vim.cmd [[autocmd User PackerComplete lua require('lvim.utils.hooks').run_on_packer_complete()]] +  if in_headless then +    init_opts.display = nil +  end + +  if vim.fn.empty(vim.fn.glob(install_path)) > 0 then +    vim.fn.system { "git", "clone", "--depth", "1", "https://github.com/wbthomason/packer.nvim", install_path } +    vim.cmd "packadd packer.nvim" +    -- IMPORTANT: we only set this the very first time to avoid constantly triggering the rollback function +    -- https://github.com/wbthomason/packer.nvim/blob/c576ab3f1488ee86d60fd340d01ade08dcabd256/lua/packer.lua#L998-L995 +    init_opts.snapshot = default_snapshot +  end + +  local status_ok, packer = pcall(require, "packer") +  if status_ok then +    packer.on_complete = vim.schedule_wrap(function() +      require("lvim.utils.hooks").run_on_packer_complete() +    end) +    packer.init(init_opts)    end  end @@ -73,6 +77,18 @@ function plugin_loader.recompile()    end  end +function plugin_loader.reload(configurations) +  _G.packer_plugins = _G.packer_plugins or {} +  for k, v in pairs(_G.packer_plugins) do +    if k ~= "packer.nvim" then +      _G.packer_plugins[v] = nil +    end +  end +  plugin_loader.load(configurations) + +  pcall_packer_command "sync" +end +  function plugin_loader.load(configurations)    Log:debug "loading plugins configuration"    local packer_available, packer = pcall(require, "packer") @@ -81,6 +97,7 @@ function plugin_loader.load(configurations)      return    end    local status_ok, _ = xpcall(function() +    packer.reset()      packer.startup(function(use)        for _, plugins in ipairs(configurations) do          for _, plugin in ipairs(plugins) do @@ -102,21 +119,29 @@ function plugin_loader.get_core_plugins()    local list = {}    local plugins = require "lvim.plugins"    for _, item in pairs(plugins) do -    table.insert(list, item[1]:match "/(%S*)") +    if not item.disable then +      table.insert(list, item[1]:match "/(%S*)") +    end    end    return list  end -function plugin_loader.sync_core_plugins() +function plugin_loader.load_snapshot(snapshot_file) +  snapshot_file = snapshot_file or default_snapshot +  if not in_headless then +    vim.notify("Syncing core plugins is in progress..", vim.log.levels.INFO, { title = "lvim" }) +  end +  Log:debug(string.format("Using snapshot file [%s]", snapshot_file))    local core_plugins = plugin_loader.get_core_plugins() -  Log:trace(string.format("Syncing core plugins: [%q]", table.concat(core_plugins, ", "))) -  pcall_packer_command("sync", core_plugins) +  require("packer").rollback(snapshot_file, unpack(core_plugins))  end -function plugin_loader.ensure_installed() -  local all_plugins = _G.packer_plugins or plugin_loader.get_core_plugins() -  Log:trace(string.format("Syncing core plugins: [%q]", table.concat(all_plugins, ", "))) -  pcall_packer_command("install", all_plugins) +function plugin_loader.sync_core_plugins() +  -- problem: rollback() will get stuck if a plugin directory doesn't exist +  -- solution: call sync() beforehand +  -- see https://github.com/wbthomason/packer.nvim/issues/862 +  vim.cmd [[autocmd User PackerComplete ++once lua require("lvim.plugin-loader").load_snapshot() ]] +  pcall_packer_command "sync"  end  return plugin_loader diff --git a/lua/lvim/plugins.lua b/lua/lvim/plugins.lua index d7ecdccb..519a203a 100644 --- a/lua/lvim/plugins.lua +++ b/lua/lvim/plugins.lua @@ -1,83 +1,44 @@ -local commit = { -  alpha_nvim = "14be0ac200f44009672046123c6fcb30724018a5", -  bufferline = "5e101b1b4e1ea5b868b8865a5f749b0b5b8f3ccd", -  cmp_buffer = "d66c4c2d376e5be99db68d2362cd94d250987525", -  cmp_luasnip = "d6f837f4e8fe48eeae288e638691b91b97d1737f", -  cmp_nvim_lsp = "ebdfc204afb87f15ce3d3d3f5df0b8181443b5ba", -  cmp_path = "466b6b8270f7ba89abd59f402c73f63c7331ff6e", -  comment = "a841f73523440c4f32d39f0290cf1e691311db2a", -  dapinstall = "24923c3819a450a772bb8f675926d530e829665f", -  fixcursorhold = "1bfb32e7ba1344925ad815cb0d7f901dbc0ff7c1", -  friendly_snippets = "ad07b2844021b20797adda5b483265802559a693", -  gitsigns = "2df360de757c39c04076cb04bcbbd361dec3c8c2", -  lua_dev = "a0ee77789d9948adce64d98700cc90cecaef88d5", -  lualine = "181b14348f513e6f9eb3bdd2252e13630094fdd3", -  luasnip = "ee350179f842699a42b3d6277b2ded8ce73bdc33", -  nlsp_settings = "ea9b88e289359843c3cc5bfbf42e5ed9cc3df5f2", -  null_ls = "041601cb03daa8982c5af6edc6641f4b97e9d6b5", -  nvim_autopairs = "6617498bea01c9c628406d7e23030da57f2f8718", -  nvim_cmp = "71d7f46b930bf08e982925c77bd9b0a9808c1162", -  nvim_dap = "3d0575a777610b364fea745b85ad497d56b8009a", -  nvim_lsp_installer = "dc783087bef65cc7c2943d8641ff1b6dfff6e5a9", -  nvim_lspconfig = "710deb04d9f8b73517e1d995a57a1505cbbaac51", -  nvim_notify = "f81b48d298c0ff7479b66568d9cc1a4794c196d0", -  nvim_tree = "20797a8d74e68bce50b98455c76c5de250c6f0e5", -  nvim_treesitter = "fd92e70c69330dd8f2f6753d3d987c34e7dacd24", -  nvim_ts_context_commentstring = "097df33c9ef5bbd3828105e4bee99965b758dc3f", -  nvim_web_devicons = "4415d1aaa56f73b9c05795af84d625c610b05d3b", -  onedarker = "b00dd2189f264c5aeb4cf04c59439655ecd573ec", -  packer = "c576ab3f1488ee86d60fd340d01ade08dcabd256", -  plenary = "14dfb4071022b22e08384ee125a5607464b6d397", -  popup = "b7404d35d5d3548a82149238289fa71f7f6de4ac", -  project = "cef52b8da07648b750d7f1e8fb93f12cb9482988", -  schemastore = "265eabf9f8ab33cc6bf1683c286b04e280a2b2e7", -  structlog = "6f1403a192791ff1fa7ac845a73de9e860f781f1", -  telescope = "a36a813d5d031e6f5d52b74986915e68130febd9", -  telescope_fzf_native = "8ec164b541327202e5e74f99bcc5fe5845720e18", -  toggleterm = "e97d0c1046512e975a9f3fa95afe98f312752b1c", -  which_key = "a3c19ec5754debb7bf38a8404e36a9287b282430", -} - -return { +local core_plugins = {    -- Packer can manage itself as an optional plugin -  { "wbthomason/packer.nvim", commit = commit.packer }, -  { "neovim/nvim-lspconfig", commit = commit.nvim_lspconfig }, -  { "tamago324/nlsp-settings.nvim", commit = commit.nlsp_settings }, +  { "wbthomason/packer.nvim" }, +  { "neovim/nvim-lspconfig" }, +  { "tamago324/nlsp-settings.nvim" },    {      "jose-elias-alvarez/null-ls.nvim", -    commit = commit.null_ls,    }, -  { "antoinemadec/FixCursorHold.nvim", commit = commit.fixcursorhold }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open +  { "antoinemadec/FixCursorHold.nvim" }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open    {      "williamboman/nvim-lsp-installer", -    commit = commit.nvim_lsp_installer,    },    {      "lunarvim/onedarker.nvim",      config = function() -      require("onedarker").setup() -      lvim.builtin.lualine.options.theme = "onedarker" +      pcall(function() +        if lvim and lvim.colorscheme == "onedarker" then +          require("onedarker").setup() +          lvim.builtin.lualine.options.theme = "onedarker" +        end +      end)      end, -    commit = commit.onedarker,      disable = lvim.colorscheme ~= "onedarker",    },    {      "rcarriga/nvim-notify", -    commit = commit.nvim_notify, +      config = function()        require("lvim.core.notify").setup()      end,      requires = { "nvim-telescope/telescope.nvim" },      disable = not lvim.builtin.notify.active or not lvim.builtin.telescope.active,    }, -  { "Tastyep/structlog.nvim", commit = commit.structlog }, +  { "Tastyep/structlog.nvim" }, -  { "nvim-lua/popup.nvim", commit = commit.popup }, -  { "nvim-lua/plenary.nvim", commit = commit.plenary }, +  { "nvim-lua/popup.nvim" }, +  { "nvim-lua/plenary.nvim" },    -- Telescope    {      "nvim-telescope/telescope.nvim", -    commit = commit.telescope, +      config = function()        require("lvim.core.telescope").setup()      end, @@ -86,14 +47,12 @@ return {    {      "nvim-telescope/telescope-fzf-native.nvim",      requires = { "nvim-telescope/telescope.nvim" }, -    commit = commit.telescope_fzf_native,      run = "make",      disable = not lvim.builtin.telescope.active,    },    -- Install nvim-cmp, and buffer source as a dependency    {      "hrsh7th/nvim-cmp", -    commit = commit.nvim_cmp,      config = function()        if lvim.builtin.cmp then          require("lvim.core.cmp").setup() @@ -106,41 +65,33 @@ return {    },    {      "rafamadriz/friendly-snippets", -    commit = commit.friendly_snippets,    },    {      "L3MON4D3/LuaSnip",      config = function()        require("luasnip/loaders/from_vscode").lazy_load()      end, -    commit = commit.luasnip,    },    {      "hrsh7th/cmp-nvim-lsp", -    commit = commit.cmp_nvim_lsp,    },    {      "saadparwaiz1/cmp_luasnip", -    commit = commit.cmp_luasnip,    },    {      "hrsh7th/cmp-buffer", -    commit = commit.cmp_buffer,    },    {      "hrsh7th/cmp-path", -    commit = commit.cmp_path,    },    {      "folke/lua-dev.nvim",      module = "lua-dev", -    commit = commit.lua_dev,    },    -- Autopairs    {      "windwp/nvim-autopairs", -    commit = commit.nvim_autopairs,      -- event = "InsertEnter",      config = function()        require("lvim.core.autopairs").setup() @@ -151,7 +102,6 @@ return {    -- Treesitter    {      "nvim-treesitter/nvim-treesitter", -    commit = commit.nvim_treesitter,      branch = vim.fn.has "nvim-0.6" == 1 and "master" or "0.5-compat",      -- run = ":TSUpdate",      config = function() @@ -160,7 +110,6 @@ return {    },    {      "JoosepAlviste/nvim-ts-context-commentstring", -    commit = commit.nvim_ts_context_commentstring,      event = "BufReadPost",    }, @@ -169,7 +118,6 @@ return {      "kyazdani42/nvim-tree.lua",      -- event = "BufWinOpen",      -- cmd = "NvimTreeToggle", -    commit = commit.nvim_tree,      config = function()        require("lvim.core.nvimtree").setup()      end, @@ -178,7 +126,6 @@ return {    {      "lewis6991/gitsigns.nvim", -    commit = commit.gitsigns,      config = function()        require("lvim.core.gitsigns").setup() @@ -190,7 +137,6 @@ return {    -- Whichkey    {      "folke/which-key.nvim", -    commit = commit.which_key,      config = function()        require("lvim.core.which-key").setup()      end, @@ -201,7 +147,6 @@ return {    -- Comments    {      "numToStr/Comment.nvim", -    commit = commit.comment,      event = "BufRead",      config = function()        require("lvim.core.comment").setup() @@ -212,7 +157,6 @@ return {    -- project.nvim    {      "ahmedkhalf/project.nvim", -    commit = commit.project,      config = function()        require("lvim.core.project").setup()      end, @@ -220,13 +164,12 @@ return {    },    -- Icons -  { "kyazdani42/nvim-web-devicons", commit = commit.nvim_web_devicons }, +  { "kyazdani42/nvim-web-devicons" },    -- Status Line and Bufferline    {      -- "hoob3rt/lualine.nvim",      "nvim-lualine/lualine.nvim", -    commit = commit.lualine,      -- "Lunarvim/lualine.nvim",      config = function()        require("lvim.core.lualine").setup() @@ -236,7 +179,6 @@ return {    {      "akinsho/bufferline.nvim", -    commit = commit.bufferline,      config = function()        require("lvim.core.bufferline").setup()      end, @@ -247,7 +189,6 @@ return {    -- Debugging    {      "mfussenegger/nvim-dap", -    commit = commit.nvim_dap,      -- event = "BufWinEnter",      config = function()        require("lvim.core.dap").setup() @@ -258,7 +199,6 @@ return {    -- Debugger management    {      "Pocco81/DAPInstall.nvim", -    commit = commit.dapinstall,      -- event = "BufWinEnter",      -- event = "BufRead",      disable = not lvim.builtin.dap.active, @@ -270,14 +210,12 @@ return {      config = function()        require("lvim.core.alpha").setup()      end, -    commit = commit.alpha_nvim,      disable = not lvim.builtin.alpha.active,    },    -- Terminal    {      "akinsho/toggleterm.nvim", -    commit = commit.toggleterm,      event = "BufWinEnter",      config = function()        require("lvim.core.terminal").setup() @@ -288,6 +226,13 @@ return {    -- SchemaStore    {      "b0o/schemastore.nvim", -    commit = commit.schemastore,    },  } + +for _, entry in ipairs(core_plugins) do +  if not os.getenv "LVIM_DEV_MODE" then +    entry["lock"] = true +  end +end + +return core_plugins diff --git a/lua/lvim/utils/git.lua b/lua/lvim/utils/git.lua index ce323160..9848835e 100644 --- a/lua/lvim/utils/git.lua +++ b/lua/lvim/utils/git.lua @@ -113,22 +113,4 @@ function M.get_lvim_current_sha()    return abbrev_version  end -function M.generate_plugins_sha(output) -  local list = {} -  output = output or "commits.lua" - -  local core_plugins = require "lvim.plugins" -  for _, plugin in pairs(core_plugins) do -    local name = plugin[1]:match "/(%S*)" -    local url = "https://github.com/" .. plugin[1] -    print("checking: " .. name .. ", at: " .. url) -    local retval, latest_sha = git_cmd { args = { "ls-remote", url, "origin", "HEAD" } } -    if retval == 0 then -      -- replace dashes, remove postfixes and use lowercase -      local normalize_name = (name:gsub("-", "_"):gsub("%.%S+", "")):lower() -      list[normalize_name] = latest_sha[1]:gsub("\tHEAD", "") -    end -  end -  require("lvim.utils").write_file(output, "local commit = " .. vim.inspect(list), "w") -end  return M diff --git a/lua/lvim/utils/hooks.lua b/lua/lvim/utils/hooks.lua index b40f2c23..932f9c3d 100644 --- a/lua/lvim/utils/hooks.lua +++ b/lua/lvim/utils/hooks.lua @@ -12,17 +12,22 @@ function M.run_pre_reload()  end  function M.run_on_packer_complete() -  if not in_headless then -    -- manually trigger event to fix colors -    vim.cmd [[ doautocmd ColorScheme ]] +  Log:debug "Packer operation complete" +  vim.cmd [[doautocmd User PackerComplete]] + +  vim.g.colors_name = lvim.colorscheme +  pcall(vim.cmd, "colorscheme " .. lvim.colorscheme) + +  if M._reload_triggered then +    Log:info "Reloaded configuration" +    M._reload_triggered = nil    end -  Log:info "Reloaded configuration"  end  function M.run_post_reload()    Log:debug "Starting post-reload hook" -  require("lvim.plugin-loader").ensure_installed()    M.reset_cache() +  M._reload_triggered = true  end  ---Reset any startup cache files used by Packer and Impatient @@ -48,8 +53,8 @@ function M.run_post_update()    Log:debug "Starting post-update hook"    M.reset_cache() -  Log:debug "Updating core plugins" -  require("lvim.plugin-loader").ensure_installed() +  Log:debug "Syncing core plugins" +  require("lvim.plugin-loader").sync_core_plugins()    if not in_headless then      vim.schedule(function() diff --git a/snapshots/default.json b/snapshots/default.json new file mode 100644 index 00000000..10f82b6c --- /dev/null +++ b/snapshots/default.json @@ -0,0 +1,113 @@ +{ +  "Comment.nvim": { +    "commit": "0aaea32" +  }, +  "DAPInstall.nvim": { +    "commit": "24923c3" +  }, +  "FixCursorHold.nvim": { +    "commit": "1bfb32e" +  }, +  "LuaSnip": { +    "commit": "eb5b77e" +  }, +  "alpha-nvim": { +    "commit": "534a86b" +  }, +  "bufferline.nvim": { +    "commit": "004cd57" +  }, +  "cmp-buffer": { +    "commit": "d66c4c2" +  }, +  "cmp-nvim-lsp": { +    "commit": "ebdfc20" +  }, +  "cmp-path": { +    "commit": "466b6b8" +  }, +  "cmp_luasnip": { +    "commit": "b108297" +  }, +  "friendly-snippets": { +    "commit": "e302658" +  }, +  "gitsigns.nvim": { +    "commit": "83ab3ca" +  }, +  "lua-dev.nvim": { +    "commit": "a0ee777" +  }, +  "lualine.nvim": { +    "commit": "c8e5a69" +  }, +  "nlsp-settings.nvim": { +    "commit": "995b5e6" +  }, +  "null-ls.nvim": { +    "commit": "899785c" +  }, +  "nvim-autopairs": { +    "commit": "06535b1" +  }, +  "nvim-cmp": { +    "commit": "7dbe34e" +  }, +  "nvim-dap": { +    "commit": "c20c78d" +  }, +  "nvim-lsp-installer": { +    "commit": "c7f1437" +  }, +  "nvim-lspconfig": { +    "commit": "3d1baa8" +  }, +  "nvim-notify": { +    "commit": "da10302" +  }, +  "nvim-tree.lua": { +    "commit": "6368880" +  }, +  "nvim-treesitter": { +    "commit": "2472e47" +  }, +  "nvim-ts-context-commentstring": { +    "commit": "7810f1f" +  }, +  "nvim-web-devicons": { +    "commit": "09e6231" +  }, +  "onedarker.nvim": { +    "commit": "b00dd21" +  }, +  "packer.nvim": { +    "commit": "4dedd3b" +  }, +  "plenary.nvim": { +    "commit": "f9c65cd" +  }, +  "popup.nvim": { +    "commit": "b7404d3" +  }, +  "project.nvim": { +    "commit": "cef52b8" +  }, +  "schemastore.nvim": { +    "commit": "d423f6c" +  }, +  "structlog.nvim": { +    "commit": "6f1403a" +  }, +  "telescope-fzf-native.nvim": { +    "commit": "8ec164b" +  }, +  "telescope.nvim": { +    "commit": "6e7ee38" +  }, +  "toggleterm.nvim": { +    "commit": "5733b24" +  }, +  "which-key.nvim": { +    "commit": "a3c19ec" +  } +} diff --git a/tests/helpers.lua b/tests/lvim/helpers.lua index ada83267..2d8477de 100644 --- a/tests/helpers.lua +++ b/tests/lvim/helpers.lua @@ -13,11 +13,11 @@ function M.search_file(file, args)        end,      })      :sync() -  return stdout, ret, stderr +  return ret, stdout, stderr  end  function M.file_contains(file, query) -  local stdout, ret, stderr = M.search_file(file, query) +  local ret, stdout, stderr = M.search_file(file, query)    if ret == 0 then      return true    end @@ -32,7 +32,7 @@ end  function M.log_contains(query)    local logfile = require("lvim.core.log"):get_path() -  local stdout, ret, stderr = M.search_file(logfile, query) +  local ret, stdout, stderr = M.search_file(logfile, query)    if ret == 0 then      return true    end @@ -42,9 +42,6 @@ function M.log_contains(query)    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 diff --git a/tests/minimal_init.lua b/tests/minimal_init.lua index 0178514b..91579243 100644 --- a/tests/minimal_init.lua +++ b/tests/minimal_init.lua @@ -2,11 +2,11 @@ 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 = { base_dir, tests_dir, os.getenv "VIMRUNTIME" } +vim.opt.rtp:append(tests_dir) +vim.opt.rtp:append(base_dir) -vim.opt.swapfile = false +require("lvim.bootstrap"):init(base_dir) --- load helper functions before any other plugin to avoid name-collisions -pcall(require, "tests.helpers") - -require("lvim.bootstrap"):init() +-- NOTE: careful about name collisions +-- see https://github.com/nvim-lualine/lualine.nvim/pull/621 +require "tests.lvim.helpers" diff --git a/tests/specs/config_loader_spec.lua b/tests/specs/config_loader_spec.lua index 54cb4e96..1f2debc7 100644 --- a/tests/specs/config_loader_spec.lua +++ b/tests/specs/config_loader_spec.lua @@ -21,25 +21,31 @@ a.describe("config-loader", function()      local test_path = "/tmp/lvim"      os.execute(string.format([[echo "vim.opt.undodir = '%s'" >> %s]], test_path, user_config_path))      config:reload() -    assert.equal(vim.opt.undodir:get()[1], test_path) +    vim.schedule(function() +      assert.equal(vim.opt.undodir:get()[1], test_path) +    end)    end)    a.it("should not get interrupted by errors in user-config", function()      local test_path = "/tmp/lunarvim"      os.execute(string.format([[echo "vim.opt.undodir = '%s'" >> %s]], test_path, user_config_path))      config:reload() -    assert.equal(vim.opt.undodir:get()[1], test_path) +    vim.schedule(function() +      assert.equal(vim.opt.undodir:get()[1], test_path) +    end)      os.execute(string.format("echo 'bad_string_test' >> %s", user_config_path))      local error_handler = function(msg)        return msg      end      local err = xpcall(config:reload(), error_handler)      assert.falsy(err) -    assert.equal(vim.opt.undodir:get()[1], test_path) -    local errmsg = vim.fn.eval "v:errmsg" -    local exception = vim.fn.eval "v:exception" -    assert.equal("", errmsg) -- v:errmsg was not updated. -    assert.equal("", exception) -    os.execute(string.format("echo '' > %s", user_config_path)) +    vim.schedule(function() +      assert.equal(vim.opt.undodir:get()[1], test_path) +      local errmsg = vim.fn.eval "v:errmsg" +      local exception = vim.fn.eval "v:exception" +      assert.equal("", errmsg) -- v:errmsg was not updated. +      assert.equal("", exception) +      os.execute(string.format("echo '' > %s", user_config_path)) +    end)    end)  end) diff --git a/tests/specs/lsp_spec.lua b/tests/specs/lsp_spec.lua index 388a24bb..2518b237 100644 --- a/tests/specs/lsp_spec.lua +++ b/tests/specs/lsp_spec.lua @@ -1,6 +1,6 @@  local a = require "plenary.async_lib.tests"  local utils = require "lvim.utils" -local helpers = require "tests.helpers" +local helpers = require "tests.lvim.helpers"  local temp_dir = vim.loop.os_getenv "TEMP" or "/tmp"  lvim.lsp.templates_dir = join_paths(temp_dir, "lvim", "tests", "artifacts") @@ -31,7 +31,7 @@ a.describe("lsp workflow", function()      lvim.log.level = "debug"      local plugins = require "lvim.plugins" -    require("lvim.plugin-loader"):load { plugins, lvim.plugins } +    require("lvim.plugin-loader").load { plugins, lvim.plugins }      if utils.is_file(logfile) then        assert.equal(vim.fn.delete(logfile), 0) @@ -51,8 +51,9 @@ a.describe("lsp workflow", function()      require("lvim.lsp").setup()      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(helpers.file_contains(file, server)) +      for _, server_name in ipairs(lvim.lsp.override) do +        local setup_cmd = string.format([[require("lvim.lsp.manager").setup(%q)]], server_name) +        assert.False(helpers.file_contains(file, setup_cmd))        end      end    end) diff --git a/tests/specs/plugins_load_spec.lua b/tests/specs/plugins_load_spec.lua index 08c96c12..d32c521d 100644 --- a/tests/specs/plugins_load_spec.lua +++ b/tests/specs/plugins_load_spec.lua @@ -5,7 +5,7 @@ a.describe("plugin-loader", function()    local loader = require "lvim.plugin-loader"    a.it("should be able to load default packages without errors", function() -    loader:load { plugins, lvim.plugins } +    loader.load { plugins, lvim.plugins }      -- TODO: maybe there's a way to avoid hard-coding the names of the modules?      local startup_plugins = { @@ -18,7 +18,7 @@ a.describe("plugin-loader", function()    end)    a.it("should be able to load lsp packages without errors", function() -    loader:load { plugins, lvim.plugins } +    loader.load { plugins, lvim.plugins }      require("lvim.lsp").setup() @@ -32,4 +32,36 @@ a.describe("plugin-loader", function()        assert.truthy(package.loaded[plugin])      end    end) +  a.it("should be able to rollback plugins without errors", function() +    local plugin = { name = "onedarker.nvim" } +    plugin.path = vim.tbl_filter(function(package) +      return package:match(plugin.name) +    end, vim.api.nvim_list_runtime_paths())[1] + +    local get_current_sha = function(repo) +      local res = vim.fn.system(string.format("git -C %s log -1 --pretty=%%h", repo)):gsub("\n", "") +      return res +    end +    plugin.test_sha = "316b1c9" +    _G.locked_sha = get_current_sha(plugin.path) +    loader.load { plugins, lvim.plugins } + +    os.execute(string.format("git -C %s fetch --deepen 999 --quiet", plugin.path)) +    os.execute(string.format("git -C %s checkout %s --quiet", plugin.path, plugin.test_sha)) +    assert.equal(plugin.test_sha, get_current_sha(plugin.path)) +    _G.completed = false +    _G.verify_sha = function() +      if _G.locked_sha ~= get_current_sha(plugin.path) then +        error "unmached results!" +      else +        _G.completed = true +      end +    end +    vim.cmd [[autocmd User PackerComplete ++once lua _G.verify_sha()]] +    loader.load_snapshot() +    local ret = vim.wait(30 * 10 * 1000, function() +      return _G.completed == true +    end, 200) +    assert.True(ret) +  end)  end) diff --git a/utils/ci/generate_new_lockfile.lua b/utils/ci/generate_new_lockfile.lua new file mode 100644 index 00000000..9f274597 --- /dev/null +++ b/utils/ci/generate_new_lockfile.lua @@ -0,0 +1,114 @@ +local sp = os.getenv "SNAPSHOT_PATH" + +local function call_proc(process, opts, cb) +  local std_output = "" +  local error_output = "" + +  local function onread(_, is_stderr) +    return function(err, data) +      if data then +        if is_stderr then +          error_output = (error_output or "") .. err +        else +          std_output = (std_output or "") .. data +        end +      end +    end +  end + +  local uv = vim.loop +  local handle + +  local stdout = uv.new_pipe(false) +  local stderr = uv.new_pipe(false) + +  local stdio = { nil, stdout, stderr } + +  handle = uv.spawn( +    process, +    { args = opts.args, cwd = uv.cwd(), stdio = stdio }, +    vim.schedule_wrap(function(code) +      if code ~= 0 then +        stdout:read_stop() +        stderr:read_stop() +      end + +      local check = uv.new_check() +      check:start(function() +        for _, pipe in ipairs(stdio) do +          if pipe and not pipe:is_closing() then +            return +          end +        end +        check:stop() +        handle:close() +        cb(code, std_output, error_output) +      end) +    end) +  ) + +  uv.read_start(stdout, onread(handle, false)) +  uv.read_start(stderr, onread(handle, true)) + +  return handle +end + +local plugins_list = {} + +local completed = 0 + +local function write_lockfile(verbose) +  local default_plugins = {} +  local active_jobs = {} + +  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] +    local commit = "" +    table.insert(default_plugins, { +      name = name, +      url = url, +      commit = commit, +    }) +  end + +  table.sort(default_plugins, function(a, b) +    return a.name < b.name +  end) + +  for _, entry in pairs(default_plugins) do +    local on_done = function(success, result, errors) +      completed = completed + 1 +      if not success then +        print("error: " .. errors) +        return +      end +      local latest_sha = result:gsub("\tHEAD\n", ""):sub(1, 7) +      plugins_list[entry.name] = { +        commit = latest_sha, +      } +    end + +    local handle = call_proc("git", { args = { "ls-remote", entry.url, "HEAD" } }, on_done) +    table.insert(active_jobs, handle) +  end + +  print("active: " .. #active_jobs) +  print("parsers: " .. #default_plugins) + +  vim.wait(#active_jobs * 60 * 1000, function() +    return completed == #active_jobs +  end) + +  if verbose then +    print(vim.inspect(plugins_list)) +  end + +  local fd = assert(io.open(sp, "w")) +  fd:write(vim.json.encode(plugins_list), "\n") +  fd:flush() +end + +write_lockfile() +vim.cmd "q" diff --git a/utils/ci/generate_new_lockfile.sh b/utils/ci/generate_new_lockfile.sh new file mode 100644 index 00000000..077df41f --- /dev/null +++ b/utils/ci/generate_new_lockfile.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -e + +REPO_DIR=$(git rev-parse --show-toplevel) + +export SNAPSHOT_NAME="default.json" +export SNAPSHOT_DIR="${REPO_DIR}/snapshots" + +mkdir -p "${SNAPSHOT_DIR}" + +export SNAPSHOT_PATH="${REPO_DIR}/snapshots/${SNAPSHOT_NAME}" + +time lvim --headless \ +  -c "luafile ./utils/ci/generate_new_lockfile.lua" + +temp=$(mktemp) + +jq --sort-keys . "${SNAPSHOT_PATH}" >"${temp}" +mv "${temp}" "${SNAPSHOT_PATH}" diff --git a/utils/installer/config.example.lua b/utils/installer/config.example.lua index 4ea98fbe..409235a5 100644 --- a/utils/installer/config.example.lua +++ b/utils/installer/config.example.lua @@ -46,10 +46,10 @@ lvim.keys.normal_mode["<C-s>"] = ":w<cr>"  --   name = "+Trouble",  --   r = { "<cmd>Trouble lsp_references<cr>", "References" },  --   f = { "<cmd>Trouble lsp_definitions<cr>", "Definitions" }, ---   d = { "<cmd>Trouble lsp_document_diagnostics<cr>", "Diagnostics" }, +--   d = { "<cmd>Trouble document_diagnostics<cr>", "Diagnostics" },  --   q = { "<cmd>Trouble quickfix<cr>", "QuickFix" },  --   l = { "<cmd>Trouble loclist<cr>", "LocationList" }, ---   w = { "<cmd>Trouble lsp_workspace_diagnostics<cr>", "Diagnostics" }, +--   w = { "<cmd>Trouble workspace_diagnostics<cr>", "Wordspace Diagnostics" },  -- }  -- TODO: User Config for predefined plugins diff --git a/utils/installer/config_win.example.lua b/utils/installer/config_win.example.lua index 9c9888a8..ecfbd1e4 100644 --- a/utils/installer/config_win.example.lua +++ b/utils/installer/config_win.example.lua @@ -63,10 +63,10 @@ lvim.keys.normal_mode["<C-s>"] = ":w<cr>"  --   name = "+Trouble",  --   r = { "<cmd>Trouble lsp_references<cr>", "References" },  --   f = { "<cmd>Trouble lsp_definitions<cr>", "Definitions" }, ---   d = { "<cmd>Trouble lsp_document_diagnostics<cr>", "Diagnostics" }, +--   d = { "<cmd>Trouble document_diagnostics<cr>", "Diagnostics" },  --   q = { "<cmd>Trouble quickfix<cr>", "QuickFix" },  --   l = { "<cmd>Trouble loclist<cr>", "LocationList" }, ---   w = { "<cmd>Trouble lsp_workspace_diagnostics<cr>", "Diagnostics" }, +--   w = { "<cmd>Trouble workspace_diagnostics<cr>", "Workspace Diagnostics" },  -- }  -- After changing plugin config exit and reopen LunarVim, Run :PackerInstall :PackerCompile diff --git a/utils/installer/install.ps1 b/utils/installer/install.ps1 index bef15ac2..182e7bac 100644 --- a/utils/installer/install.ps1 +++ b/utils/installer/install.ps1 @@ -267,7 +267,7 @@ function create_alias {          return      } -    Add-Content -Path $PROFILE -Value $("Set-Alias lvim $lvim_bin") +    Add-Content -Path $PROFILE -Value $("`r`nSet-Alias lvim $lvim_bin")      Write-Host 'To use the new alias in this window reload your profile with: `. $PROFILE`' -ForegroundColor Green  } diff --git a/utils/installer/uninstall.ps1 b/utils/installer/uninstall.ps1 index 4d6ffa5d..2de21037 100644 --- a/utils/installer/uninstall.ps1 +++ b/utils/installer/uninstall.ps1 @@ -49,9 +49,15 @@ function remove_lvim_dirs($force) {          if (Test-Path $dir) {
              Remove-Item -Force -Recurse $dir
          }
 -        if ($force -eq $true -and (Test-Path "$dir.bak" -or Test-Path "$dir.old")) {
 -            Remove-Item -Force -Recurse "$dir.{bak,old}"
 +        if ($force -eq $true) {
 +            if (Test-Path "$dir.bak") {
 +                Remove-Item -Force -Recurse "$dir.bak"
 +            }
 +            if (Test-Path "$dir.old") {
 +                Remove-Item -Force -Recurse "$dir.old"
 +            }
          }
      }
  }
 +main($args)
\ No newline at end of file | 
