├── pack └── packer │ └── start │ └── packer.nvim │ ├── selene.toml │ ├── tests │ ├── minimal.vim │ ├── helpers.lua │ ├── packer_use_spec.lua │ ├── packer_plugin_utils_spec.lua │ ├── local_plugin_spec.lua │ ├── plugin_utils_spec.lua │ └── snapshot_spec.lua │ ├── stylua.toml │ ├── lua │ └── packer │ │ ├── handlers.lua │ │ ├── plugin_types.lua │ │ ├── result.lua │ │ ├── install.lua │ │ ├── plugin_types │ │ ├── local.lua │ │ └── git.lua │ │ ├── clean.lua │ │ ├── async.lua │ │ ├── util.lua │ │ ├── log.lua │ │ ├── update.lua │ │ ├── load.lua │ │ ├── snapshot.lua │ │ ├── jobs.lua │ │ ├── plugin_utils.lua │ │ ├── luarocks.lua │ │ └── compile.lua │ ├── Makefile │ ├── .gitignore │ ├── Dockerfile │ ├── .lua-format │ ├── vim.toml │ └── LICENSE ├── .luarc.json ├── lua ├── colorscheme.lua ├── .luarc.json ├── completion.lua ├── utils.lua ├── settings.lua ├── lspmappings.lua ├── plugins_lazy.lua ├── plugins.lua ├── keymappings.lua ├── coc.lua └── pluginconfigs.lua ├── compose.yaml ├── README.md ├── init.lua ├── Dockerfile ├── lazy-lock.json └── plugin └── packer_compiled.lua /pack/packer/start/packer.nvim/selene.toml: -------------------------------------------------------------------------------- 1 | std="vim" 2 | -------------------------------------------------------------------------------- /.luarc.json: -------------------------------------------------------------------------------- 1 | { 2 | "diagnostics.globals": [ 3 | "printHello" 4 | ] 5 | } -------------------------------------------------------------------------------- /lua/colorscheme.lua: -------------------------------------------------------------------------------- 1 | vim.cmd 'colorscheme everforest' 2 | vim.cmd 'set termguicolors' 3 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/tests/minimal.vim: -------------------------------------------------------------------------------- 1 | set rtp+=. 2 | set rtp+=../plenary.nvim 3 | runtime! plugin/plenary.vim 4 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/stylua.toml: -------------------------------------------------------------------------------- 1 | indent_type = "Spaces" 2 | indent_width = 2 3 | quote_style = "AutoPreferSingle" 4 | no_call_parentheses = true 5 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/handlers.lua: -------------------------------------------------------------------------------- 1 | local config = nil 2 | 3 | local function cfg(_config) 4 | config = _config 5 | end 6 | 7 | local handlers = { 8 | cfg = cfg, 9 | } 10 | 11 | return handlers 12 | -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | networks: 2 | neovim-local: 3 | 4 | services: 5 | neovim-dev: 6 | container_name: neovim-dev 7 | build: . 8 | environment: 9 | TEST_ENV: "Test ENV" 10 | volumes: 11 | - ./:/root/.config/nvim/ 12 | working_dir: /root/ 13 | stdin_open: true 14 | tty: true 15 | networks: 16 | - neovim-local 17 | -------------------------------------------------------------------------------- /lua/.luarc.json: -------------------------------------------------------------------------------- 1 | { 2 | "workspace.library": [ 3 | "/Users/alexcantu/.local/share/nvim/lazy/neodev.nvim/types/stable", 4 | "/Users/alexcantu/neovim/share/nvim/runtime/lua", 5 | "/Users/alexcantu/Development/nvim_weekly_plugin_configs/lua", 6 | "${3rd}/luv/library" 7 | ], 8 | "diagnostics.globals": [ 9 | "vim" 10 | ] 11 | } -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal.vim' }" 3 | run: 4 | docker build . -t neovim-stable:latest && docker run --rm -it --entrypoint bash neovim-stable:latest 5 | run-test: 6 | docker build . -t neovim-stable:latest && docker run --rm neovim-stable:latest 7 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/plugin_types.lua: -------------------------------------------------------------------------------- 1 | local config 2 | 3 | local function cfg(_config) 4 | config = _config 5 | end 6 | 7 | local plugin_types = setmetatable({ cfg = cfg }, { 8 | __index = function(self, k) 9 | local v = require('packer.plugin_types.' .. k) 10 | v.cfg(config) 11 | self[k] = v 12 | return v 13 | end, 14 | }) 15 | 16 | return plugin_types 17 | -------------------------------------------------------------------------------- /lua/completion.lua: -------------------------------------------------------------------------------- 1 | local utils = require('utils') 2 | utils.opt('o', 'completeopt', 'menuone,noinsert,noselect') 3 | vim.cmd [[set shortmess+=c]] 4 | vim.g.completion_confirm_key = "" 5 | vim.g.completion_matching_strategy_list = {'exact', 'substring', 'fuzzy'} 6 | -- to navigate the completion menu 7 | utils.map('i', '', 'pumvisible() ? "\\" : "\\"', {expr = true}) 8 | utils.map('i', '', 'pumvisible() ? "\\" : "\\"', {expr = true}) 9 | -------------------------------------------------------------------------------- /lua/utils.lua: -------------------------------------------------------------------------------- 1 | local utils = { } 2 | 3 | local scopes = {o = vim.o, b = vim.bo, w = vim.wo} 4 | 5 | function utils.opt(scope, key, value) 6 | scopes[scope][key] = value 7 | if scope ~= 'o' then scopes['o'][key] = value end 8 | end 9 | 10 | function utils.map(mode, lhs, rhs, opts) 11 | local options = {noremap = true} 12 | if opts then options = vim.tbl_extend('force', options, opts) end 13 | vim.api.nvim_set_keymap(mode, lhs, rhs, options) 14 | end 15 | 16 | return utils 17 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | # Vim swap files 43 | *.swp 44 | 45 | doc/tags 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nvim_weekly_plugin_configs 2 | 3 | Configurations used for the weekly neovim plugin video series 4 | 5 | These instructions will walk through how to run a Docker container 6 | with neovim installed and these configurations applied. 7 | 8 | ## Running with docker compose 9 | 10 | This will run a docker container with the nvim installed from source 11 | 12 | ``` 13 | docker compose up --build -d 14 | ``` 15 | 16 | ``` 17 | docker attach neovim-dev 18 | ``` 19 | 20 | ## Setup 21 | 22 | Once attached to the container, open Neovim with the command `nvim`. 23 | You will initially get some error messages saying that plugins are not 24 | installed. That's OK. Hit `Enter` and then run `PackerInstall`. 25 | Restart neovim. 26 | 27 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/tests/helpers.lua: -------------------------------------------------------------------------------- 1 | local util = require 'packer.util' 2 | 3 | local M = { base_dir = '/tmp/__packer_tests__' } 4 | 5 | ---Create a fake git repository 6 | ---@param name string 7 | ---@param base string 8 | function M.create_git_dir(name, base) 9 | base = base or M.base_dir 10 | local repo_path = util.join_paths(base, name) 11 | local path = util.join_paths(repo_path, '.git') 12 | if vim.fn.isdirectory(path) > 0 then 13 | M.cleanup_dirs(path) 14 | end 15 | vim.fn.mkdir(path, 'p') 16 | return repo_path 17 | end 18 | 19 | ---Remove directories created for test purposes 20 | ---@vararg string 21 | function M.cleanup_dirs(...) 22 | for _, dir in ipairs { ... } do 23 | vim.fn.delete(dir, 'rf') 24 | end 25 | end 26 | 27 | return M 28 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM archlinux:base-devel 2 | WORKDIR /setup 3 | RUN pacman -Sy git neovim python --noconfirm 4 | RUN useradd -m test 5 | 6 | USER test 7 | RUN git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim 8 | RUN mkdir -p /home/test/.cache/nvim/packer.nvim 9 | RUN touch /home/test/.cache/nvim/packer.nvim/test_completion{,1,2,3} 10 | 11 | USER test 12 | RUN mkdir -p /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim/ 13 | WORKDIR /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim/ 14 | COPY . ./ 15 | 16 | USER root 17 | RUN chmod 777 -R /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim 18 | RUN touch /home/test/.cache/nvim/packer.nvim/not_writeable 19 | 20 | USER test 21 | ENTRYPOINT make test 22 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | -- Setting up leader key 2 | vim.g.mapleader = ' ' 3 | 4 | -- Initialize Lazy Plugin Manager 5 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 6 | if not vim.loop.fs_stat(lazypath) then 7 | vim.fn.system({ 8 | "git", 9 | "clone", 10 | "--filter=blob:none", 11 | "https://github.com/folke/lazy.nvim.git", 12 | "--branch=stable", -- latest stable release 13 | lazypath, 14 | }) 15 | end 16 | 17 | -- Setting up lazy, and telling it where `plugins` table is. 18 | -- We manage the `plugins` in another file 19 | vim.opt.rtp:prepend(lazypath) 20 | require('lazy').setup("plugins_lazy") 21 | -- Apply general vim settings 22 | require('settings') 23 | -- Configure plugins 24 | require('pluginconfigs') 25 | -- Colorscheme 26 | require('colorscheme') 27 | -- Key mappings 28 | require('keymappings') 29 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/.lua-format: -------------------------------------------------------------------------------- 1 | align_args: true 2 | align_parameter: true 3 | align_table_field: true 4 | break_after_functioncall_lp: false 5 | break_after_functiondef_lp: false 6 | break_after_operator: false 7 | break_after_table_lb: true 8 | break_before_functioncall_rp: true 9 | break_before_functiondef_rp: true 10 | break_before_table_rb: true 11 | chop_down_kv_table: true 12 | chop_down_parameter: true 13 | chop_down_table: false 14 | column_limit: 100 15 | column_table_limit: 100 16 | continuation_indent_width: 2 17 | double_quote_to_single_quote: false 18 | extra_sep_at_table_end: false 19 | indent_width: 2 20 | keep_simple_control_block_one_line: true 21 | keep_simple_function_one_line: true 22 | single_quote_to_double_quote: false 23 | spaces_before_call: 1 24 | tab_width: 2 25 | table_sep: ',' 26 | use_tab: false 27 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/vim.toml: -------------------------------------------------------------------------------- 1 | [selene] 2 | base = "lua51" 3 | name = "vim" 4 | 5 | [vim] 6 | any = true 7 | 8 | [jit] 9 | any = true 10 | 11 | [[describe.args]] 12 | type = "string" 13 | [[describe.args]] 14 | type = "function" 15 | 16 | [[it.args]] 17 | type = "string" 18 | [[it.args]] 19 | type = "function" 20 | 21 | [[before_each.args]] 22 | type = "function" 23 | [[after_each.args]] 24 | type = "function" 25 | 26 | [assert.is_not] 27 | any = true 28 | 29 | [[assert.equals.args]] 30 | type = "any" 31 | [[assert.equals.args]] 32 | type = "any" 33 | [[assert.equals.args]] 34 | type = "any" 35 | required = false 36 | 37 | [[assert.same.args]] 38 | type = "any" 39 | [[assert.same.args]] 40 | type = "any" 41 | 42 | [[assert.truthy.args]] 43 | type = "any" 44 | 45 | [[assert.spy.args]] 46 | type = "any" 47 | 48 | [[assert.stub.args]] 49 | type = "any" 50 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/tests/packer_use_spec.lua: -------------------------------------------------------------------------------- 1 | local packer = require("packer") 2 | local use = packer.use 3 | local packer_path = vim.fn.stdpath("data").."/site/pack/packer/start/" 4 | 5 | describe("Packer use tests", function() 6 | after_each(function() 7 | packer.reset() 8 | end) 9 | 10 | it("should set the correct install path", function () 11 | local spec = {"test/plugin1"} 12 | packer.startup(function() 13 | use(spec) 14 | end) 15 | packer.__manage_all() 16 | assert.truthy(spec.install_path) 17 | assert.equal(spec.install_path, packer_path .. spec.short_name) 18 | end) 19 | 20 | it("should add metadata to a plugin from a spec", function () 21 | local spec = {"test/plugin1"} 22 | packer.startup(function() 23 | use(spec) 24 | end) 25 | packer.__manage_all() 26 | assert.equal(spec.name, "test/plugin1") 27 | assert.equal(spec.path, "test/plugin1") 28 | end) 29 | end) 30 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/tests/packer_plugin_utils_spec.lua: -------------------------------------------------------------------------------- 1 | local a = require('plenary.async_lib.tests') 2 | local await = require('packer.async').wait 3 | local plugin_utils = require("packer.plugin_utils") 4 | local packer_path = vim.fn.stdpath("data") .. "/site/pack/packer/start/" 5 | 6 | a.describe("Packer post update hooks", function() 7 | local test_plugin_path = packer_path .. "test_plugin/" 8 | local run_hook = plugin_utils.post_update_hook 9 | 10 | before_each(function() vim.fn.mkdir(test_plugin_path, "p") end) 11 | 12 | after_each(function() vim.fn.delete(test_plugin_path, "rf") end) 13 | 14 | a.it("should run the command in the correct folder", function() 15 | local plugin_spec = { 16 | name = "test/test_plugin", 17 | install_path = test_plugin_path, 18 | run = "touch 'this_file_should_exist'" 19 | } 20 | 21 | await(run_hook(plugin_spec, {task_update = function() end})) 22 | 23 | assert.truthy(vim.loop.fs_stat(test_plugin_path .. "this_file_should_exist")) 24 | end) 25 | end) 26 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Wil Thomason 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/tests/local_plugin_spec.lua: -------------------------------------------------------------------------------- 1 | local a = require('plenary.async_lib.tests') 2 | local await = require('packer.async').wait 3 | local local_plugin = require('packer.plugin_types.local') 4 | local packer_path = vim.fn.stdpath('data') .. '/site/pack/packer/start/' 5 | local helpers = require('tests.helpers') 6 | 7 | a.describe('Local plugin -', function() 8 | a.describe('installer', function() 9 | local local_plugin_path 10 | local repo_name = 'test.nvim' 11 | local plugin_install_path = packer_path .. repo_name 12 | 13 | before_each(function() 14 | vim.fn.mkdir(packer_path, 'p') 15 | local_plugin_path = helpers.create_git_dir(repo_name) 16 | end) 17 | 18 | after_each(function() helpers.cleanup_dirs(local_plugin_path, plugin_install_path) end) 19 | 20 | a.it('should create a symlink', function() 21 | local plugin_spec = { 22 | name = local_plugin_path, 23 | path = local_plugin_path, 24 | install_path = plugin_install_path 25 | } 26 | 27 | local_plugin.setup(plugin_spec) 28 | await(plugin_spec.installer({task_update = function() end})) 29 | 30 | assert.equal('link', vim.loop.fs_lstat(plugin_install_path).type) 31 | end) 32 | end) 33 | end) 34 | -------------------------------------------------------------------------------- /lua/settings.lua: -------------------------------------------------------------------------------- 1 | local utils = require('utils') 2 | 3 | local cmd = vim.cmd 4 | local indent = 4 5 | 6 | cmd 'syntax enable' 7 | cmd 'filetype plugin indent on' 8 | cmd 'set shell=/usr/bin/zsh' 9 | utils.opt('b', 'expandtab', true) 10 | utils.opt('b', 'shiftwidth', indent) 11 | utils.opt('b', 'smartindent', true) 12 | utils.opt('o', 'hidden', true) 13 | utils.opt('o', 'ignorecase', true) 14 | utils.opt('o', 'scrolloff', 4) 15 | utils.opt('o', 'shiftround', true) 16 | utils.opt('o', 'smartcase', true) 17 | utils.opt('o', 'splitbelow', true) 18 | utils.opt('o', 'splitright', true) 19 | utils.opt('o', 'wildmode', 'list:longest') 20 | utils.opt('w', 'relativenumber', true) 21 | utils.opt('o', 'clipboard', 'unnamed,unnamedplus') 22 | 23 | --code folding 24 | utils.opt('o', 'foldcolumn', '1') 25 | utils.opt('o', 'foldlevel', 1) 26 | utils.opt('o', 'foldlevelstart', 99) 27 | utils.opt('o', 'foldenable', true) 28 | utils.opt('o', 'foldclose', 'all') 29 | 30 | -- Highlight on yank 31 | vim.cmd 'au TextYankPost * lua vim.highlight.on_yank {on_visual = false}' 32 | 33 | -- Indent blankline 34 | vim.opt.list = true 35 | vim.opt.listchars:append "eol:↴" 36 | 37 | -- which-key 38 | vim.o.timeout = true 39 | vim.o.timeoutlen = 300 40 | vim.o.mouse = '' 41 | -- undotree 42 | vim.o.undofile = true 43 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:8 2 | 3 | # Switch to CentOS stream repos 4 | # https://haydenjames.io/fix-error-failed-to-download-metadata-for-repo-appstream-centos-8/ 5 | RUN dnf --disablerepo '*' --enablerepo=extras swap centos-linux-repos centos-stream-repos -y 6 | RUN dnf distro-sync -y 7 | RUN dnf install epel-release epel-next-release -y 8 | 9 | # Install OS packages 10 | RUN yum install yum-utils -y 11 | #RUN yum-config-manager --add-repo=https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/repo/epel-7/carlwgeorge-ripgrep-epel-7.repo 12 | RUN yum install tar zip findutils util-linux-user zsh iputils procps tree diffutils mlocate tmux vim git python3 curl rust cmake ripgrep -y 13 | 14 | # Install node 15 | RUN dnf module enable nodejs:16 -y 16 | RUN dnf install nodejs xclip -y 17 | # Install pyright 18 | RUN npm install pyright --global 19 | 20 | # RUN chsh -s /bin/zsh root 21 | 22 | # Set up neovim 23 | ## Commented on 05/21/2023 So that we can build neovim from source instead 24 | RUN git clone https://github.com/neovim/neovim.git /root/neovim 25 | ## Install version v0.9.5 and build from source 26 | RUN cd /root/neovim && git checkout v0.9.5 && make CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$HOME/neovim" 27 | RUN cd /root/neovim && make install 28 | RUN echo 'export PATH="$HOME/neovim/bin:$PATH"' >> /root/.bashrc 29 | RUN mkdir -p /root/.locl/share/nvim/site/autoload 30 | RUN echo 'alias vi=nvim' >> /root/.bashrc 31 | 32 | # Set WORKDIR 33 | WORKDIR /root/ 34 | 35 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/result.lua: -------------------------------------------------------------------------------- 1 | -- A simple Result type to simplify control flow with installers and updaters 2 | local result = {} 3 | 4 | local ok_result_mt = { 5 | and_then = function(self, f, ...) 6 | local r = f(...) 7 | if r == nil then 8 | return result.err('Nil result in and_then! ' .. vim.inspect(debug.traceback())) 9 | end 10 | 11 | self.ok = r.ok 12 | self.err = r.err 13 | setmetatable(self, getmetatable(r)) 14 | return self 15 | end, 16 | or_else = function(self) 17 | return self 18 | end, 19 | map_ok = function(self, f) 20 | self.ok = f(self.ok) or self.ok 21 | return self 22 | end, 23 | map_err = function(self) 24 | return self 25 | end, 26 | } 27 | 28 | ok_result_mt.__index = ok_result_mt 29 | 30 | local err_result_mt = { 31 | and_then = function(self) 32 | return self 33 | end, 34 | or_else = function(self, f, ...) 35 | local r = f(...) 36 | if r == nil then 37 | return result.err('Nil result in or_else! ' .. vim.inspect(debug.traceback())) 38 | end 39 | 40 | self.ok = r.ok 41 | self.err = r.err 42 | setmetatable(self, getmetatable(r)) 43 | return self 44 | end, 45 | map_ok = function(self) 46 | return self 47 | end, 48 | map_err = function(self, f) 49 | self.err = f(self.err) or self.err 50 | return self 51 | end, 52 | } 53 | 54 | err_result_mt.__index = err_result_mt 55 | 56 | result.ok = function(val) 57 | if val == nil then 58 | val = true 59 | end 60 | local r = setmetatable({}, ok_result_mt) 61 | r.ok = val 62 | return r 63 | end 64 | 65 | result.err = function(err) 66 | if err == nil then 67 | err = true 68 | end 69 | local r = setmetatable({}, err_result_mt) 70 | r.err = err 71 | return r 72 | end 73 | 74 | return result 75 | -------------------------------------------------------------------------------- /lua/lspmappings.lua: -------------------------------------------------------------------------------- 1 | -- Global mappings. 2 | -- See `:help vim.diagnostic.*` for documentation on any of the below functions 3 | vim.keymap.set('n', 'e', vim.diagnostic.open_float) 4 | vim.keymap.set('n', '[d', vim.diagnostic.goto_prev) 5 | vim.keymap.set('n', ']d', vim.diagnostic.goto_next) 6 | vim.keymap.set('n', 'q', vim.diagnostic.setloclist) 7 | 8 | -- Use LspAttach autocommand to only map the following keys 9 | -- after the language server attaches to the current buffer 10 | vim.api.nvim_create_autocmd('LspAttach', { 11 | group = vim.api.nvim_create_augroup('UserLspConfig', {}), 12 | callback = function(ev) 13 | -- Enable completion triggered by 14 | vim.bo[ev.buf].omnifunc = 'v:lua.vim.lsp.omnifunc' 15 | 16 | -- Buffer local mappings. 17 | -- See `:help vim.lsp.*` for documentation on any of the below functions 18 | local opts = { buffer = ev.buf } 19 | vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts) 20 | vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) 21 | vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) 22 | vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts) 23 | vim.keymap.set('n', '', vim.lsp.buf.signature_help, opts) 24 | vim.keymap.set('i', '', vim.lsp.buf.signature_help, opts) 25 | vim.keymap.set('n', 'wa', vim.lsp.buf.add_workspace_folder, opts) 26 | vim.keymap.set('n', 'wr', vim.lsp.buf.remove_workspace_folder, opts) 27 | vim.keymap.set('n', 'wl', function() 28 | print(vim.inspect(vim.lsp.buf.list_workspace_folders())) 29 | end, opts) 30 | vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, opts) 31 | vim.keymap.set('n', 'rn', vim.lsp.buf.rename, opts) 32 | vim.keymap.set({ 'n', 'v' }, 'ca', vim.lsp.buf.code_action, opts) 33 | vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) 34 | vim.keymap.set('n', 'f', function() 35 | vim.lsp.buf.format { async = true } 36 | end, opts) 37 | end, 38 | }) 39 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/install.lua: -------------------------------------------------------------------------------- 1 | local a = require 'packer.async' 2 | local log = require 'packer.log' 3 | local util = require 'packer.util' 4 | local display = require 'packer.display' 5 | local plugin_utils = require 'packer.plugin_utils' 6 | 7 | local fmt = string.format 8 | local async = a.sync 9 | local await = a.wait 10 | 11 | local config = nil 12 | 13 | local function install_plugin(plugin, display_win, results) 14 | local plugin_name = util.get_plugin_full_name(plugin) 15 | return async(function() 16 | display_win:task_start(plugin_name, 'installing...') 17 | -- TODO: If the user provided a custom function as an installer, we would like to use pcall 18 | -- here. Need to figure out how that integrates with async code 19 | local r = await(plugin.installer(display_win)) 20 | r = r:and_then(await, plugin_utils.post_update_hook(plugin, display_win)) 21 | if r.ok then 22 | display_win:task_succeeded(plugin_name, 'installed') 23 | log.debug('Installed ' .. plugin_name) 24 | else 25 | display_win:task_failed(plugin_name, 'failed to install') 26 | log.debug(fmt('Failed to install %s: %s', plugin_name, vim.inspect(r.err))) 27 | end 28 | 29 | results.installs[plugin_name] = r 30 | results.plugins[plugin_name] = plugin 31 | end) 32 | end 33 | 34 | local function do_install(_, plugins, missing_plugins, results) 35 | results = results or {} 36 | results.installs = results.installs or {} 37 | results.plugins = results.plugins or {} 38 | local display_win = nil 39 | local tasks = {} 40 | if #missing_plugins > 0 then 41 | display_win = display.open(config.display.open_fn or config.display.open_cmd) 42 | for _, v in ipairs(missing_plugins) do 43 | if not plugins[v].disable then 44 | table.insert(tasks, install_plugin(plugins[v], display_win, results)) 45 | end 46 | end 47 | end 48 | 49 | return tasks, display_win 50 | end 51 | 52 | local function cfg(_config) 53 | config = _config 54 | end 55 | 56 | local install = setmetatable({ cfg = cfg }, { __call = do_install }) 57 | 58 | return install 59 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/plugin_types/local.lua: -------------------------------------------------------------------------------- 1 | local a = require 'packer.async' 2 | local log = require 'packer.log' 3 | local util = require 'packer.util' 4 | local result = require 'packer.result' 5 | 6 | local async = a.sync 7 | local await = a.wait 8 | local fmt = string.format 9 | 10 | local config = nil 11 | local function cfg(_config) 12 | config = _config 13 | end 14 | 15 | -- Due to #679, we know that fs_symlink requires admin privileges on Windows. This is a workaround, 16 | -- as suggested by @nonsleepr. 17 | 18 | local symlink_fn 19 | if util.is_windows then 20 | symlink_fn = function(path, new_path, flags, callback) 21 | flags = flags or {} 22 | flags.junction = true 23 | return vim.loop.fs_symlink(path, new_path, flags, callback) 24 | end 25 | else 26 | symlink_fn = vim.loop.fs_symlink 27 | end 28 | 29 | local symlink = a.wrap(symlink_fn) 30 | local unlink = a.wrap(vim.loop.fs_unlink) 31 | 32 | local function setup_local(plugin) 33 | local from = vim.loop.fs_realpath(util.strip_trailing_sep(plugin.path)) 34 | local to = util.strip_trailing_sep(plugin.install_path) 35 | 36 | local plugin_name = util.get_plugin_full_name(plugin) 37 | plugin.installer = function(disp) 38 | return async(function() 39 | disp:task_update(plugin_name, 'making symlink...') 40 | local err, success = await(symlink(from, to, { dir = true })) 41 | if not success then 42 | plugin.output = { err = { err } } 43 | return result.err(err) 44 | end 45 | return result.ok() 46 | end) 47 | end 48 | 49 | plugin.updater = function(disp) 50 | return async(function() 51 | local r = result.ok() 52 | disp:task_update(plugin_name, 'checking symlink...') 53 | local resolved_path = vim.loop.fs_realpath(to) 54 | if resolved_path ~= from then 55 | disp:task_update(plugin_name, 'updating symlink...') 56 | r = await(unlink(to)):and_then(symlink(from, to, { dir = true })) 57 | end 58 | 59 | return r 60 | end) 61 | end 62 | 63 | plugin.revert_last = function(_) 64 | log.warn "Can't revert a local plugin!" 65 | return result.ok() 66 | end 67 | end 68 | 69 | return { setup = setup_local, cfg = cfg } 70 | -------------------------------------------------------------------------------- /lua/plugins_lazy.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 'sainnhe/everforest' }, 3 | { "akinsho/toggleterm.nvim" }, 4 | { 'nvim-tree/nvim-tree.lua' }, 5 | -- ufo, for code folding 6 | { 7 | 'kevinhwang91/nvim-ufo', 8 | dependencies = { 'kevinhwang91/promise-async' }, 9 | }, 10 | { "lukas-reineke/indent-blankline.nvim", tag = "v2.20.8" }, 11 | { "nvim-treesitter/nvim-treesitter" }, 12 | -- treesj - 08/25/2023 13 | { 'Wansmer/treesj' }, 14 | { 'numToStr/Comment.nvim' }, 15 | { 16 | 'nvim-telescope/telescope.nvim', 17 | dependencies = { 'nvim-lua/plenary.nvim' }, 18 | }, 19 | 20 | { 21 | 'nvim-lualine/lualine.nvim', 22 | dependencies = { 'nvim-tree/nvim-web-devicons' }, 23 | }, 24 | { 'ThePrimeagen/harpoon' }, 25 | { 26 | 'akinsho/bufferline.nvim', 27 | tag = 'v4.4.0', 28 | }, 29 | { 30 | 'folke/which-key.nvim', 31 | tag = 'v1.5.1', 32 | }, 33 | { 'folke/flash.nvim' }, 34 | --nvim-cmp 35 | { 'hrsh7th/cmp-buffer' }, 36 | { 'hrsh7th/cmp-path' }, 37 | { 'hrsh7th/cmp-cmdline' }, 38 | { 'hrsh7th/nvim-cmp' }, 39 | { 'hrsh7th/cmp-vsnip' }, 40 | { 'hrsh7th/vim-vsnip' }, 41 | { 'rafamadriz/friendly-snippets' }, 42 | -- vim surround 43 | { 'tpope/vim-surround' }, 44 | -- gp 45 | { 'robitx/gp.nvim' }, 46 | -- Make sure the following LSP plugins are in this order. 47 | { 48 | 'williamboman/mason.nvim', 49 | lazy = false, 50 | }, 51 | { 52 | 'williamboman/mason-lspconfig.nvim', 53 | lazy = false, 54 | }, 55 | { 'neovim/nvim-lspconfig' }, 56 | { 'hrsh7th/cmp-nvim-lsp' }, 57 | { 58 | "folke/noice.nvim", 59 | event = "VeryLazy", 60 | opts = { 61 | -- add any options here 62 | }, 63 | dependencies = { 64 | "MunifTanjim/nui.nvim", 65 | "rcarriga/nvim-notify", 66 | } 67 | }, 68 | 'nvim-pack/nvim-spectre', 69 | 'mbbill/undotree', 70 | 'lewis6991/gitsigns.nvim', 71 | 'nvimdev/lspsaga.nvim', 72 | { "folke/neodev.nvim", opts = {} }, 73 | { 74 | 'mg979/vim-visual-multi', 75 | -- See https://github.com/mg979/vim-visual-multi/issues/241 76 | init = function() 77 | vim.g.VM_default_mappings = 0 78 | vim.g.VM_maps = { 79 | ['Find Under'] = '' 80 | } 81 | vim.g.VM_add_cursor_at_pos_no_mappings = 1 82 | end, 83 | }, 84 | } 85 | -------------------------------------------------------------------------------- /lua/plugins.lua: -------------------------------------------------------------------------------- 1 | ---@diagnostic disable: undefined-global 2 | return require('packer').startup(function() 3 | -- Packer can manage itself as an optional plugin 4 | use { 'wbthomason/packer.nvim', opt = true } 5 | 6 | -- Color scheme 7 | use { 'sainnhe/everforest' } 8 | 9 | use { "akinsho/toggleterm.nvim", tag = '*', config = function() 10 | require("toggleterm").setup({ 11 | close_on_exit = false, 12 | autochdir = true, 13 | shell = vim.o.shell, 14 | size = 20 15 | }) 16 | end } 17 | use { 'nvim-tree/nvim-tree.lua' } 18 | 19 | -- neogit 20 | use { 'treatybreaker/neogit', requires = 'nvim-lua/plenary.nvim', config = function() 21 | require('neogit').setup() 22 | end 23 | } 24 | 25 | -- diffview 26 | use { "sindrets/diffview.nvim", 27 | config = function() 28 | require('diffview').setup() 29 | end 30 | } 31 | 32 | -- New plugins as of 08/04/2023 33 | -- nvim.coc 34 | use { 'neoclide/coc.nvim', branch = 'release' } 35 | 36 | -- ufo, for code folding 37 | use { 'kevinhwang91/nvim-ufo', requires = 'kevinhwang91/promise-async' } 38 | 39 | -- Indent blankline 40 | use {"lukas-reineke/indent-blankline.nvim", 41 | tag = "v2.20.8", 42 | } 43 | 44 | -- Treesitter 45 | use {"nvim-treesitter/nvim-treesitter"} 46 | 47 | -- treesj - 08/25/2023 48 | use({'Wansmer/treesj', 49 | -- Treesitter functions depending on what 'parsers' are installed. 50 | -- For more info, see: 51 | -- https://github.com/nvim-treesitter/nvim-treesitter#language-parsers 52 | -- 2023-08-05 16:26 53 | requires = { 'nvim-treesitter/nvim-treesitter' }, 54 | }) 55 | 56 | use {'numToStr/Comment.nvim'} 57 | 58 | use {'nvim-telescope/telescope.nvim', 59 | requires = { {'nvim-lua/plenary.nvim'} }, 60 | } 61 | 62 | use {'nvim-lualine/lualine.nvim', 63 | requires = { 'nvim-tree/nvim-web-devicons', opt = true } 64 | } 65 | 66 | -- harpoon 67 | -- Plenary dependency isn't defined because Telescope already has it defined 68 | -- as a dependency 69 | use {'ThePrimeagen/harpoon'} 70 | 71 | -- bufferline 72 | use {'akinsho/bufferline.nvim', tag = 'v4.4.0'} 73 | 74 | -- which-key 75 | use {'folke/which-key.nvim', tag = 'v1.5.1'} 76 | 77 | -- flask 78 | use {'folke/flash.nvim', tag = 'v1.18.2'} 79 | 80 | --nvim-cmp 81 | use {'hrsh7th/cmp-buffer'} 82 | use {'hrsh7th/cmp-path'} 83 | use {'hrsh7th/cmp-cmdline'} 84 | use {'hrsh7th/nvim-cmp'} 85 | 86 | use {'hrsh7th/cmp-vsnip'} 87 | use {'hrsh7th/vim-vsnip'} 88 | use {'rafamadriz/friendly-snippets'} 89 | 90 | -- vim surround 91 | use {'tpope/vim-surround'} 92 | 93 | -- gp 94 | use {'robitx/gp.nvim'} 95 | end) 96 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/tests/plugin_utils_spec.lua: -------------------------------------------------------------------------------- 1 | local a = require('plenary.async_lib.tests') 2 | local await = require('packer.async').wait 3 | local async = require('packer.async').sync 4 | local plugin_utils = require('packer.plugin_utils') 5 | local helpers = require("tests.helpers") 6 | 7 | local fmt = string.format 8 | 9 | a.describe('Plugin utils -', function() 10 | 11 | a.describe('find_missing_plugins', function() 12 | local repo_name = "test.nvim" 13 | local path 14 | 15 | plugin_utils.cfg({start_dir = helpers.base_dir}) 16 | 17 | before_each(function() path = helpers.create_git_dir(repo_name) end) 18 | 19 | after_each(function() helpers.cleanup_dirs("tmp/packer") end) 20 | 21 | a.it('should pick up plugins with a different remote URL', function() 22 | local test_repo_name = fmt('user2/%s', repo_name) 23 | local plugins = { 24 | [repo_name] = { 25 | opt = false, 26 | type = "git", 27 | name = fmt("user1/%s", repo_name), 28 | short_name = repo_name, 29 | remote_url = function() 30 | return async(function() 31 | return {ok = {remote = fmt('https://github.com/%s', test_repo_name)}} 32 | end) 33 | end 34 | } 35 | } 36 | local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true})) 37 | assert.truthy(result) 38 | assert.equal(1, #vim.tbl_keys(result)) 39 | end) 40 | 41 | a.it('should not pick up plugins with the same remote URL', function() 42 | local test_repo_name = fmt('user1/%s', repo_name) 43 | local plugins = { 44 | [repo_name] = { 45 | opt = false, 46 | type = "git", 47 | name = test_repo_name, 48 | short_name = repo_name, 49 | remote_url = function() 50 | return async(function() 51 | return {ok = {remote = fmt('https://github.com/%s', test_repo_name)}} 52 | end) 53 | end 54 | } 55 | } 56 | local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true})) 57 | assert.truthy(result) 58 | assert.equal(0, #result) 59 | end) 60 | 61 | a.it('should handle ssh git urls', function() 62 | local test_repo_name = fmt('user2/%s', repo_name) 63 | local plugins = { 64 | [repo_name] = { 65 | opt = false, 66 | type = "git", 67 | name = fmt("user1/%s", repo_name), 68 | short_name = repo_name, 69 | remote_url = function() 70 | return async(function() 71 | return {ok = {remote = fmt('git@github.com:%s.git', test_repo_name)}} 72 | end) 73 | end 74 | } 75 | } 76 | local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true})) 77 | assert.truthy(result) 78 | assert.equal(1, #vim.tbl_keys(result)) 79 | end) 80 | end) 81 | end) 82 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/clean.lua: -------------------------------------------------------------------------------- 1 | local plugin_utils = require 'packer.plugin_utils' 2 | local a = require 'packer.async' 3 | local display = require 'packer.display' 4 | local log = require 'packer.log' 5 | local util = require 'packer.util' 6 | 7 | local await = a.wait 8 | local async = a.sync 9 | 10 | local config 11 | 12 | local PLUGIN_OPTIONAL_LIST = 1 13 | local PLUGIN_START_LIST = 2 14 | 15 | local function is_dirty(plugin, typ) 16 | return (plugin.opt and typ == PLUGIN_START_LIST) or (not plugin.opt and typ == PLUGIN_OPTIONAL_LIST) 17 | end 18 | 19 | -- Find and remove any plugins not currently configured for use 20 | local clean_plugins = function(_, plugins, fs_state, results) 21 | return async(function() 22 | log.debug 'Starting clean' 23 | local dirty_plugins = {} 24 | results = results or {} 25 | results.removals = results.removals or {} 26 | local opt_plugins = vim.deepcopy(fs_state.opt) 27 | local start_plugins = vim.deepcopy(fs_state.start) 28 | local missing_plugins = fs_state.missing 29 | -- test for dirty / 'missing' plugins 30 | for _, plugin_config in pairs(plugins) do 31 | local path = plugin_config.install_path 32 | local plugin_source = nil 33 | if opt_plugins[path] then 34 | plugin_source = PLUGIN_OPTIONAL_LIST 35 | opt_plugins[path] = nil 36 | elseif start_plugins[path] then 37 | plugin_source = PLUGIN_START_LIST 38 | start_plugins[path] = nil 39 | end 40 | 41 | -- We don't want to report paths which don't exist for removal; that will confuse people 42 | local path_exists = false 43 | if missing_plugins[plugin_config.short_name] or plugin_config.disable then 44 | path_exists = vim.loop.fs_stat(path) ~= nil 45 | end 46 | 47 | local plugin_missing = path_exists and missing_plugins[plugin_config.short_name] 48 | local disabled_but_installed = path_exists and plugin_config.disable 49 | if plugin_missing or is_dirty(plugin_config, plugin_source) or disabled_but_installed then 50 | dirty_plugins[#dirty_plugins + 1] = path 51 | end 52 | end 53 | 54 | -- Any path which was not set to `nil` above will be set to dirty here 55 | local function mark_remaining_as_dirty(plugin_list) 56 | for path, _ in pairs(plugin_list) do 57 | dirty_plugins[#dirty_plugins + 1] = path 58 | end 59 | end 60 | 61 | mark_remaining_as_dirty(opt_plugins) 62 | mark_remaining_as_dirty(start_plugins) 63 | if next(dirty_plugins) then 64 | local lines = {} 65 | for _, path in ipairs(dirty_plugins) do 66 | table.insert(lines, ' - ' .. path) 67 | end 68 | await(a.main) 69 | if config.autoremove or await(display.ask_user('Removing the following directories. OK? (y/N)', lines)) then 70 | results.removals = dirty_plugins 71 | log.debug('Removed ' .. vim.inspect(dirty_plugins)) 72 | for _, path in ipairs(dirty_plugins) do 73 | local result = vim.fn.delete(path, 'rf') 74 | if result == -1 then 75 | log.warn('Could not remove ' .. path) 76 | end 77 | end 78 | else 79 | log.warn 'Cleaning cancelled!' 80 | end 81 | else 82 | log.info 'Already clean!' 83 | end 84 | end) 85 | end 86 | 87 | local function cfg(_config) 88 | config = _config 89 | end 90 | 91 | local clean = setmetatable({ cfg = cfg }, { __call = clean_plugins }) 92 | return clean 93 | -------------------------------------------------------------------------------- /lazy-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "Comment.nvim": { "branch": "master", "commit": "0236521ea582747b58869cb72f70ccfa967d2e89" }, 3 | "bufferline.nvim": { "branch": "main", "commit": "6ecd37e0fa8b156099daedd2191130e083fb1490" }, 4 | "cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" }, 5 | "cmp-cmdline": { "branch": "main", "commit": "8ee981b4a91f536f52add291594e89fb6645e451" }, 6 | "cmp-nvim-lsp": { "branch": "main", "commit": "5af77f54de1b16c34b23cba810150689a3a90312" }, 7 | "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, 8 | "cmp-vsnip": { "branch": "main", "commit": "989a8a73c44e926199bfd05fa7a516d51f2d2752" }, 9 | "everforest": { "branch": "master", "commit": "89080db9637bb297b4c75ae1511e9f6f61ad9c78" }, 10 | "flash.nvim": { "branch": "main", "commit": "48817af25f51c0590653bbc290866e4890fe1cbe" }, 11 | "friendly-snippets": { "branch": "main", "commit": "b8fae73a479ae0a1c54f5c98fa687ae8a0addc53" }, 12 | "gitsigns.nvim": { "branch": "main", "commit": "2c2463dbd82eddd7dbab881c3a62cfbfbe3c67ae" }, 13 | "gp.nvim": { "branch": "main", "commit": "607f94d361f36b8eabb148d95993604fdd74d901" }, 14 | "harpoon": { "branch": "master", "commit": "ccae1b9bec717ae284906b0bf83d720e59d12b91" }, 15 | "indent-blankline.nvim": { "branch": "master", "commit": "9637670896b68805430e2f72cf5d16be5b97a22a" }, 16 | "lazy.nvim": { "branch": "main", "commit": "bef521ac89c8d423f9d092e37b58e8af0c099309" }, 17 | "lspsaga.nvim": { "branch": "main", "commit": "d5aa1a02a23b5725054928426b1de6932a6d3bc3" }, 18 | "lualine.nvim": { "branch": "master", "commit": "7d131a8d3ba5016229e8a1d08bf8782acea98852" }, 19 | "mason-lspconfig.nvim": { "branch": "main", "commit": "2b3d247fce06f53934174f5dfe0362c42d65c00c" }, 20 | "mason.nvim": { "branch": "main", "commit": "c43eeb5614a09dc17c03a7fb49de2e05de203924" }, 21 | "neodev.nvim": { "branch": "main", "commit": "ce9a2e8eaba5649b553529c5498acb43a6c317cd" }, 22 | "noice.nvim": { "branch": "main", "commit": "bf67d70bd7265d075191e7812d8eb42b9791f737" }, 23 | "nui.nvim": { "branch": "main", "commit": "35da9ca1de0fc4dda96c2e214d93d363c145f418" }, 24 | "nvim-cmp": { "branch": "main", "commit": "538e37ba87284942c1d76ed38dd497e54e65b891" }, 25 | "nvim-lspconfig": { "branch": "master", "commit": "ac530dfb97e51d82e3b0a7cddbf7a4a7c4c10ff8" }, 26 | "nvim-notify": { "branch": "master", "commit": "80b67b265530632505193553d05127ae7fe09ddd" }, 27 | "nvim-spectre": { "branch": "master", "commit": "6a0785ef64c839d935a2f92e20988e962fb6537e" }, 28 | "nvim-tree.lua": { "branch": "master", "commit": "f39f7b6fcd3865ac2146de4cb4045286308f2935" }, 29 | "nvim-treesitter": { "branch": "master", "commit": "5fca7ae4960c415af0b038e89a2d84ef6e16d28d" }, 30 | "nvim-ufo": { "branch": "main", "commit": "b0741a647efd98d9abb6cb653e056d24a07e4581" }, 31 | "nvim-web-devicons": { "branch": "master", "commit": "aaec87dbdaa776bfa0a13c8694bec9bcb7454719" }, 32 | "plenary.nvim": { "branch": "master", "commit": "4f71c0c4a196ceb656c824a70792f3df3ce6bb6d" }, 33 | "promise-async": { "branch": "main", "commit": "94f6f03c6c1e2aab551aacdf0c1e597a7269abb6" }, 34 | "telescope.nvim": { "branch": "master", "commit": "7b5c5f56a21e82fdcfe5b250278b8dfc4b1cbab4" }, 35 | "toggleterm.nvim": { "branch": "main", "commit": "b49df5cdce67a8964d1b027dae94bde212092b51" }, 36 | "treesj": { "branch": "main", "commit": "14808da3cddd62fc86ede53a5ea1fd1635897e75" }, 37 | "undotree": { "branch": "master", "commit": "9dbbf3b7d19dda0d22ceca461818e4739ad8154d" }, 38 | "vim-surround": { "branch": "master", "commit": "3d188ed2113431cf8dac77be61b842acb64433d9" }, 39 | "vim-visual-multi": { "branch": "master", "commit": "b84a6d42c1c10678928b0bf8327f378c8bc8af5a" }, 40 | "vim-vsnip": { "branch": "master", "commit": "02a8e79295c9733434aab4e0e2b8c4b7cea9f3a9" }, 41 | "which-key.nvim": { "branch": "main", "commit": "bf09a25bdc9a83bcc69d2cf078e680368676513b" } 42 | } -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/async.lua: -------------------------------------------------------------------------------- 1 | -- Adapted from https://ms-jpq.github.io/neovim-async-tutorial/ 2 | local log = require 'packer.log' 3 | local yield = coroutine.yield 4 | local resume = coroutine.resume 5 | local thread_create = coroutine.create 6 | 7 | local function EMPTY_CALLBACK() end 8 | local function step(func, callback) 9 | local thread = thread_create(func) 10 | local tick = nil 11 | tick = function(...) 12 | local ok, val = resume(thread, ...) 13 | if ok then 14 | if type(val) == 'function' then 15 | val(tick) 16 | else 17 | (callback or EMPTY_CALLBACK)(val) 18 | end 19 | else 20 | log.error('Error in coroutine: ' .. val); 21 | (callback or EMPTY_CALLBACK)(nil) 22 | end 23 | end 24 | 25 | tick() 26 | end 27 | 28 | local function wrap(func) 29 | return function(...) 30 | local params = { ... } 31 | return function(tick) 32 | params[#params + 1] = tick 33 | return func(unpack(params)) 34 | end 35 | end 36 | end 37 | 38 | local function join(...) 39 | local thunks = { ... } 40 | local thunk_all = function(s) 41 | if #thunks == 0 then 42 | return s() 43 | end 44 | local to_go = #thunks 45 | local results = {} 46 | for i, thunk in ipairs(thunks) do 47 | local callback = function(...) 48 | results[i] = { ... } 49 | if to_go == 1 then 50 | s(unpack(results)) 51 | else 52 | to_go = to_go - 1 53 | end 54 | end 55 | 56 | thunk(callback) 57 | end 58 | end 59 | 60 | return thunk_all 61 | end 62 | 63 | local function wait_all(...) 64 | return yield(join(...)) 65 | end 66 | 67 | local function pool(n, interrupt_check, ...) 68 | local thunks = { ... } 69 | return function(s) 70 | if #thunks == 0 then 71 | return s() 72 | end 73 | local remaining = { select(n + 1, unpack(thunks)) } 74 | local results = {} 75 | local to_go = #thunks 76 | local make_callback = nil 77 | make_callback = function(idx, left) 78 | local i = (left == nil) and idx or (idx + left) 79 | return function(...) 80 | results[i] = { ... } 81 | to_go = to_go - 1 82 | if to_go == 0 then 83 | s(unpack(results)) 84 | elseif not interrupt_check or not interrupt_check() then 85 | if remaining and #remaining > 0 then 86 | local next_task = table.remove(remaining) 87 | next_task(make_callback(n, #remaining + 1)) 88 | end 89 | end 90 | end 91 | end 92 | 93 | for i = 1, math.min(n, #thunks) do 94 | local thunk = thunks[i] 95 | thunk(make_callback(i)) 96 | end 97 | end 98 | end 99 | 100 | local function wait_pool(limit, ...) 101 | return yield(pool(limit, false, ...)) 102 | end 103 | 104 | local function interruptible_wait_pool(limit, interrupt_check, ...) 105 | return yield(pool(limit, interrupt_check, ...)) 106 | end 107 | 108 | local function main(f) 109 | vim.schedule(f) 110 | end 111 | 112 | local M = { 113 | --- Wrapper for functions that do not take a callback to make async functions 114 | sync = wrap(step), 115 | --- Alias for yielding to await the result of an async function 116 | wait = yield, 117 | --- Await the completion of a full set of async functions 118 | wait_all = wait_all, 119 | --- Await the completion of a full set of async functions, with a limit on how many functions can 120 | -- run simultaneously 121 | wait_pool = wait_pool, 122 | --- Like wait_pool, but additionally checks at every function completion to see if a condition is 123 | -- met indicating that it should keep running the remaining tasks 124 | interruptible_wait_pool = interruptible_wait_pool, 125 | --- Wrapper for functions that do take a callback to make async functions 126 | wrap = wrap, 127 | --- Convenience function to ensure a function runs on the main "thread" (i.e. for functions which 128 | -- use Neovim functions, etc.) 129 | main = main, 130 | } 131 | 132 | return M 133 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/util.lua: -------------------------------------------------------------------------------- 1 | local util = {} 2 | 3 | util.map = function(func, seq) 4 | local result = {} 5 | for _, v in ipairs(seq) do 6 | table.insert(result, func(v)) 7 | end 8 | 9 | return result 10 | end 11 | 12 | util.partition = function(sub, seq) 13 | local sub_vals = {} 14 | for _, val in ipairs(sub) do 15 | sub_vals[val] = true 16 | end 17 | 18 | local result = { {}, {} } 19 | for _, val in ipairs(seq) do 20 | if sub_vals[val] then 21 | table.insert(result[1], val) 22 | else 23 | table.insert(result[2], val) 24 | end 25 | end 26 | 27 | return unpack(result) 28 | end 29 | 30 | util.nonempty_or = function(opt, alt) 31 | if #opt > 0 then 32 | return opt 33 | else 34 | return alt 35 | end 36 | end 37 | 38 | if jit ~= nil then 39 | util.is_windows = jit.os == 'Windows' 40 | else 41 | util.is_windows = package.config:sub(1, 1) == '\\' 42 | end 43 | 44 | if util.is_windows and vim.o.shellslash then 45 | util.use_shellslash = true 46 | else 47 | util.use_shallslash = false 48 | end 49 | 50 | util.get_separator = function() 51 | if util.is_windows and not util.use_shellslash then 52 | return '\\' 53 | end 54 | return '/' 55 | end 56 | 57 | util.strip_trailing_sep = function(path) 58 | local res, _ = string.gsub(path, util.get_separator() .. '$', '', 1) 59 | return res 60 | end 61 | 62 | util.join_paths = function(...) 63 | local separator = util.get_separator() 64 | return table.concat({ ... }, separator) 65 | end 66 | 67 | util.get_plugin_short_name = function(plugin) 68 | local path = vim.fn.expand(plugin[1]) 69 | local name_segments = vim.split(path, util.get_separator()) 70 | local segment_idx = #name_segments 71 | local name = plugin.as or name_segments[segment_idx] 72 | while name == '' and segment_idx > 0 do 73 | name = name_segments[segment_idx] 74 | segment_idx = segment_idx - 1 75 | end 76 | return name, path 77 | end 78 | 79 | util.get_plugin_full_name = function(plugin) 80 | local plugin_name = plugin.name 81 | if plugin.branch and plugin.branch ~= 'master' then 82 | -- NOTE: maybe have to change the seperator here too 83 | plugin_name = plugin_name .. '/' .. plugin.branch 84 | end 85 | 86 | if plugin.rev then 87 | plugin_name = plugin_name .. '@' .. plugin.rev 88 | end 89 | 90 | return plugin_name 91 | end 92 | 93 | util.remove_ending_git_url = function(url) 94 | return vim.endswith(url, '.git') and url:sub(1, -5) or url 95 | end 96 | 97 | util.deep_extend = function(policy, ...) 98 | local result = {} 99 | local function helper(policy, k, v1, v2) 100 | if type(v1) ~= 'table' or type(v2) ~= 'table' then 101 | if policy == 'error' then 102 | error('Key ' .. vim.inspect(k) .. ' is already present with value ' .. vim.inspect(v1)) 103 | elseif policy == 'force' then 104 | return v2 105 | else 106 | return v1 107 | end 108 | else 109 | return util.deep_extend(policy, v1, v2) 110 | end 111 | end 112 | 113 | for _, t in ipairs { ... } do 114 | for k, v in pairs(t) do 115 | if result[k] ~= nil then 116 | result[k] = helper(policy, k, result[k], v) 117 | else 118 | result[k] = v 119 | end 120 | end 121 | end 122 | 123 | return result 124 | end 125 | 126 | -- Credit to @crs for the original function 127 | util.float = function(opts) 128 | local last_win = vim.api.nvim_get_current_win() 129 | local last_pos = vim.api.nvim_win_get_cursor(last_win) 130 | local columns = vim.o.columns 131 | local lines = vim.o.lines 132 | local width = math.ceil(columns * 0.8) 133 | local height = math.ceil(lines * 0.8 - 4) 134 | local left = math.ceil((columns - width) * 0.5) 135 | local top = math.ceil((lines - height) * 0.5 - 1) 136 | 137 | --- TODO: this is an impromptu fix for 138 | --- https://github.com/wbthomason/packer.nvim/pull/325#issuecomment-832874005 139 | --- ideally we should decide if the string argument passed to display openers is 140 | --- required or not 141 | if type(opts) ~= 'table' then 142 | opts = {} 143 | end 144 | 145 | opts = vim.tbl_deep_extend('force', { 146 | relative = 'editor', 147 | style = 'minimal', 148 | border = 'double', 149 | width = width, 150 | height = height, 151 | col = left, 152 | row = top, 153 | }, opts or {}) 154 | 155 | local buf = vim.api.nvim_create_buf(false, true) 156 | local win = vim.api.nvim_open_win(buf, true, opts) 157 | 158 | function _G.__packer_restore_cursor() 159 | vim.api.nvim_set_current_win(last_win) 160 | vim.api.nvim_win_set_cursor(last_win, last_pos) 161 | end 162 | 163 | vim.cmd 'autocmd! BufWipeout lua __packer_restore_cursor()' 164 | 165 | return true, win, buf 166 | end 167 | 168 | return util 169 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/log.lua: -------------------------------------------------------------------------------- 1 | -- log.lua 2 | -- 3 | -- Inspired by rxi/log.lua 4 | -- Modified by tjdevries and can be found at github.com/tjdevries/vlog.nvim 5 | -- 6 | -- This library is free software; you can redistribute it and/or modify it 7 | -- under the terms of the MIT license. See LICENSE for details. 8 | -- User configuration section 9 | local default_config = { 10 | -- Name of the plugin. Prepended to log messages 11 | plugin = 'packer.nvim', 12 | 13 | -- Should print the output to neovim while running 14 | use_console = true, 15 | 16 | -- Should highlighting be used in console (using echohl) 17 | highlights = true, 18 | 19 | -- Should write to a file 20 | use_file = true, 21 | 22 | -- Any messages above this level will be logged. 23 | level = 'debug', 24 | 25 | -- Level configuration 26 | modes = { 27 | { name = 'trace', hl = 'Comment' }, 28 | { name = 'debug', hl = 'Comment' }, 29 | { name = 'info', hl = 'None' }, 30 | { name = 'warn', hl = 'WarningMsg' }, 31 | { name = 'error', hl = 'ErrorMsg' }, 32 | { name = 'fatal', hl = 'ErrorMsg' }, 33 | }, 34 | 35 | -- Which levels should be logged? 36 | active_levels = { [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true }, 37 | 38 | -- Can limit the number of decimals displayed for floats 39 | float_precision = 0.01, 40 | } 41 | 42 | -- {{{ NO NEED TO CHANGE 43 | local log = {} 44 | 45 | local unpack = unpack or table.unpack 46 | 47 | local level_ids = { trace = 1, debug = 2, info = 3, warn = 4, error = 5, fatal = 6 } 48 | log.cfg = function(_config) 49 | local min_active_level = level_ids[_config.log.level] 50 | local config = { active_levels = {} } 51 | if min_active_level then 52 | for i = min_active_level, 6 do 53 | config.active_levels[i] = true 54 | end 55 | end 56 | log.new(config, true) 57 | end 58 | 59 | log.new = function(config, standalone) 60 | config = vim.tbl_deep_extend('force', default_config, config) 61 | local outfile = string.format('%s/%s.log', vim.fn.stdpath 'cache', config.plugin) 62 | vim.fn.mkdir(vim.fn.stdpath 'cache', 'p') 63 | local obj 64 | if standalone then 65 | obj = log 66 | else 67 | obj = {} 68 | end 69 | 70 | local levels = {} 71 | for i, v in ipairs(config.modes) do 72 | levels[v.name] = i 73 | end 74 | 75 | local round = function(x, increment) 76 | increment = increment or 1 77 | x = x / increment 78 | return (x > 0 and math.floor(x + 0.5) or math.ceil(x - 0.5)) * increment 79 | end 80 | 81 | local make_string = function(...) 82 | local t = {} 83 | for i = 1, select('#', ...) do 84 | local x = select(i, ...) 85 | 86 | if type(x) == 'number' and config.float_precision then 87 | x = tostring(round(x, config.float_precision)) 88 | elseif type(x) == 'table' then 89 | x = vim.inspect(x) 90 | else 91 | x = tostring(x) 92 | end 93 | 94 | t[#t + 1] = x 95 | end 96 | return table.concat(t, ' ') 97 | end 98 | 99 | local console_output = vim.schedule_wrap(function(level_config, info, nameupper, msg) 100 | local console_lineinfo = vim.fn.fnamemodify(info.short_src, ':t') .. ':' .. info.currentline 101 | local console_string = string.format('[%-6s%s] %s: %s', nameupper, os.date '%H:%M:%S', console_lineinfo, msg) 102 | -- Heuristic to check for nvim-notify 103 | local is_fancy_notify = type(vim.notify) == 'table' 104 | vim.notify( 105 | string.format([[%s%s]], is_fancy_notify and '' or ('[' .. config.plugin .. '] '), console_string), 106 | vim.log.levels[level_config.name:upper()], 107 | { title = config.plugin } 108 | ) 109 | end) 110 | 111 | local log_at_level = function(level, level_config, message_maker, ...) 112 | -- Return early if we're below the config.level 113 | if level < levels[config.level] then 114 | return 115 | end 116 | local nameupper = level_config.name:upper() 117 | 118 | local msg = message_maker(...) 119 | local info = debug.getinfo(2, 'Sl') 120 | local lineinfo = info.short_src .. ':' .. info.currentline 121 | 122 | -- Output to console 123 | if config.use_console and config.active_levels[level] then 124 | console_output(level_config, info, nameupper, msg) 125 | end 126 | 127 | -- Output to log file 128 | if config.use_file and config.active_levels[level] then 129 | local fp, err = io.open(outfile, 'a') 130 | if not fp then 131 | print(err) 132 | return 133 | end 134 | 135 | local str = string.format('[%-6s%s %s] %s: %s\n', nameupper, os.date(), vim.loop.hrtime(), lineinfo, msg) 136 | fp:write(str) 137 | fp:close() 138 | end 139 | end 140 | 141 | for i, x in ipairs(config.modes) do 142 | obj[x.name] = function(...) 143 | return log_at_level(i, x, make_string, ...) 144 | end 145 | 146 | obj[('fmt_%s'):format(x.name)] = function() 147 | return log_at_level(i, x, function(...) 148 | local passed = { ... } 149 | local fmt = table.remove(passed, 1) 150 | local inspected = {} 151 | for _, v in ipairs(passed) do 152 | table.insert(inspected, vim.inspect(v)) 153 | end 154 | return string.format(fmt, unpack(inspected)) 155 | end) 156 | end 157 | end 158 | end 159 | 160 | log.new(default_config, true) 161 | -- }}} 162 | 163 | return log 164 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/update.lua: -------------------------------------------------------------------------------- 1 | local util = require 'packer.util' 2 | local result = require 'packer.result' 3 | local display = require 'packer.display' 4 | local a = require 'packer.async' 5 | local log = require 'packer.log' 6 | local plugin_utils = require 'packer.plugin_utils' 7 | 8 | local fmt = string.format 9 | local async = a.sync 10 | local await = a.wait 11 | 12 | local config = nil 13 | 14 | local function get_plugin_status(plugins, plugin_name, start_plugins, opt_plugins) 15 | local status = {} 16 | local plugin = plugins[plugin_name] 17 | status.wrong_type = (plugin.opt and vim.tbl_contains(start_plugins, util.join_paths(config.start_dir, plugin_name))) 18 | or vim.tbl_contains(opt_plugins, util.join_paths(config.opt_dir, plugin_name)) 19 | return status 20 | end 21 | 22 | local function cfg(_config) 23 | config = _config 24 | end 25 | 26 | local function fix_plugin_type(plugin, results, fs_state) 27 | local from 28 | local to 29 | if plugin.opt then 30 | from = util.join_paths(config.start_dir, plugin.short_name) 31 | to = util.join_paths(config.opt_dir, plugin.short_name) 32 | fs_state.opt[to] = true 33 | fs_state.start[from] = nil 34 | fs_state.missing[plugin.short_name] = nil 35 | else 36 | from = util.join_paths(config.opt_dir, plugin.short_name) 37 | to = util.join_paths(config.start_dir, plugin.short_name) 38 | fs_state.start[to] = true 39 | fs_state.opt[from] = nil 40 | fs_state.missing[plugin.short_name] = nil 41 | end 42 | 43 | -- NOTE: If we stored all plugins somewhere off-package-path and used symlinks to put them in the 44 | -- right directories, this could be lighter-weight 45 | local success, msg = os.rename(from, to) 46 | if not success then 47 | log.error('Failed to move ' .. from .. ' to ' .. to .. ': ' .. msg) 48 | results.moves[plugin.short_name] = { from = from, to = to, result = result.err(success) } 49 | else 50 | log.debug('Moved ' .. plugin.short_name .. ' from ' .. from .. ' to ' .. to) 51 | results.moves[plugin.short_name] = { from = from, to = to, result = result.ok(success) } 52 | end 53 | end 54 | 55 | local function fix_plugin_types(plugins, plugin_names, results, fs_state) 56 | log.debug 'Fixing plugin types' 57 | results = results or {} 58 | results.moves = results.moves or {} 59 | -- NOTE: This function can only be run on plugins already installed 60 | for _, v in ipairs(plugin_names) do 61 | local plugin = plugins[v] 62 | local install_dir = util.join_paths(plugin.opt and config.start_dir or config.opt_dir, plugin.short_name) 63 | if vim.loop.fs_stat(install_dir) ~= nil then 64 | fix_plugin_type(plugin, results, fs_state) 65 | end 66 | end 67 | log.debug 'Done fixing plugin types' 68 | end 69 | 70 | local function update_plugin(plugin, display_win, results, opts) 71 | local plugin_name = util.get_plugin_full_name(plugin) 72 | -- TODO: This will have to change when separate packages are implemented 73 | local install_path = util.join_paths(config.pack_dir, plugin.opt and 'opt' or 'start', plugin.short_name) 74 | plugin.install_path = install_path 75 | return async(function() 76 | if plugin.lock or plugin.disable then 77 | return 78 | end 79 | display_win:task_start(plugin_name, 'updating...') 80 | local r = await(plugin.updater(display_win, opts)) 81 | if r ~= nil and r.ok then 82 | local msg = 'up to date' 83 | if plugin.type == plugin_utils.git_plugin_type then 84 | local info = r.info 85 | local actual_update = info.revs[1] ~= info.revs[2] 86 | msg = actual_update and ('updated: ' .. info.revs[1] .. '...' .. info.revs[2]) or 'already up to date' 87 | if actual_update and not opts.preview_updates then 88 | log.debug(fmt('Updated %s: %s', plugin_name, vim.inspect(info))) 89 | r = r:and_then(await, plugin_utils.post_update_hook(plugin, display_win)) 90 | end 91 | end 92 | 93 | if r.ok then 94 | display_win:task_succeeded(plugin_name, msg) 95 | end 96 | else 97 | display_win:task_failed(plugin_name, 'failed to update') 98 | local errmsg = '' 99 | if r ~= nil and r.err ~= nil then 100 | errmsg = r.err 101 | end 102 | log.debug(fmt('Failed to update %s: %s', plugin_name, vim.inspect(errmsg))) 103 | end 104 | 105 | results.updates[plugin_name] = r 106 | results.plugins[plugin_name] = plugin 107 | end) 108 | end 109 | 110 | local function do_update(_, plugins, update_plugins, display_win, results, opts) 111 | results = results or {} 112 | results.updates = results.updates or {} 113 | results.plugins = results.plugins or {} 114 | local tasks = {} 115 | for _, v in ipairs(update_plugins) do 116 | local plugin = plugins[v] 117 | if plugin == nil then 118 | log.error(fmt('Unknown plugin: %s', v)) 119 | end 120 | if plugin and not plugin.frozen then 121 | if display_win == nil then 122 | display_win = display.open(config.display.open_fn or config.display.open_cmd) 123 | end 124 | 125 | table.insert(tasks, update_plugin(plugin, display_win, results, opts)) 126 | end 127 | end 128 | 129 | if #tasks == 0 then 130 | log.info 'Nothing to update!' 131 | end 132 | 133 | return tasks, display_win 134 | end 135 | 136 | local update = setmetatable({ cfg = cfg }, { __call = do_update }) 137 | 138 | update.get_plugin_status = get_plugin_status 139 | update.fix_plugin_types = fix_plugin_types 140 | 141 | return update 142 | -------------------------------------------------------------------------------- /lua/keymappings.lua: -------------------------------------------------------------------------------- 1 | local utils = require('utils') 2 | local wk = require("which-key") 3 | -- ToggleTerm Key Mappings 4 | utils.map('i', [[]], 'exe v:count1 . "ToggleTerm size=80 direction=vertical"') 5 | utils.map('n', [[]], 'exe v:count1 . "ToggleTerm size=80 direction=vertical"') 6 | 7 | -- bufferline 8 | utils.map('n', [[gb]], ':BufferLinePick') 9 | 10 | -- Nvim Tree Key Mappings 11 | utils.map('i', [[]], ':NvimTreeToggle') 12 | utils.map('n', [[]], ':NvimTreeToggle') 13 | 14 | 15 | -- toggle term 16 | function _G.set_terminal_keymaps() 17 | local opts = { noremap = true } 18 | vim.api.nvim_buf_set_keymap(0, 't', '', [[]], opts) 19 | vim.api.nvim_buf_set_keymap(0, 't', '', [[k]], opts) 20 | end 21 | 22 | vim.cmd('autocmd! TermOpen term://* lua set_terminal_keymaps()') 23 | 24 | -- ufo code folding 25 | vim.keymap.set('n', 'zN', require('ufo').openAllFolds) 26 | vim.keymap.set('n', 'zM', require('ufo').closeAllFolds) 27 | 28 | -- telescope keymappings 29 | local builtin = require('telescope.builtin') 30 | vim.keymap.set('n', 'ff', builtin.find_files, {}) 31 | vim.keymap.set('n', 'fg', builtin.live_grep, {}) 32 | vim.keymap.set('n', 'fb', builtin.buffers, {}) 33 | vim.keymap.set('n', 'fh', builtin.help_tags, {}) 34 | 35 | -- harpoon 36 | -- vim.keymap.set('n', 'hx', require('harpoon.mark').add_file) 37 | vim.keymap.set('n', 'hn', require('harpoon.ui').nav_next) 38 | vim.keymap.set('n', 'hp', require('harpoon.ui').nav_prev) 39 | utils.map('n', [[hm]], ':Telescope harpoon marks') 40 | 41 | -- Harpoon Which-key mappings 42 | wk.register({ 43 | -- The first key you are pressing 44 | h = { 45 | name = "harpoon", 46 | -- the second key 47 | x = { function() 48 | require('harpoon.mark').add_file() 49 | end, "Mark file" } 50 | }, 51 | }, { prefix = "" }) 52 | 53 | -- bufferline 54 | utils.map( 55 | 'n', 56 | [[bl]], 57 | ':BufferLinePick' 58 | ) 59 | print("hello") 60 | -- flash 61 | wk.register({ 62 | -- flash search 63 | l = { 64 | name = "flash", 65 | s = { function() require("flash").jump() end, "Flash Jump" }, 66 | t = { function() require("flash").treesitter() end, "Flash Treesitter" }, 67 | r = { function() require("flash").treesitter_search() end, "Flash Treesitter Search" }, 68 | }, 69 | }, { prefix = "" }) 70 | 71 | -- gp (Chat GPT) 72 | wk.register({ 73 | u = { 74 | name = "Chat GPT", 75 | g = { "GpChatToggle popup", "Toggle Chat" }, 76 | r = { "GpChatRespond", "Respond" }, 77 | n = { "GpChatNew popup", "New Chat" }, 78 | } 79 | }, { mode = "n", prefix = "" }) 80 | 81 | wk.register({ 82 | g = { 83 | name = "Gitsigns", 84 | s = { "lua require('gitsigns').stage_hunk()", "Stage Hunk" }, 85 | u = { "lua require('gitsigns').undo_stage_hunk()", "Undo Stage Hunk" }, 86 | r = { "lua require('gitsigns').reset_hunk()", "Reset Hunk" }, 87 | p = { "lua require('gitsigns').preview_hunk()", "Preview Hunk" }, 88 | b = { "lua require('gitsigns').blame_line()", "Blame Line" }, 89 | f = { "lua require('gitsigns').diffthis('~1')", "Diff This" }, 90 | n = { "lua require('gitsigns').next_hunk()", "Blame Line" }, 91 | } 92 | }, { prefix = "" }) 93 | 94 | -- spectre 95 | vim.keymap.set('n', 'S', 'lua require("spectre").toggle()', { 96 | desc = "Toggle Spectre" 97 | }) 98 | vim.keymap.set('n', 'sw', 'lua require("spectre").open_visual({select_word=true})', { 99 | desc = "Search current word" 100 | }) 101 | vim.keymap.set('v', 'sw', 'lua require("spectre").open_visual()', { 102 | desc = "Search current word" 103 | }) 104 | vim.keymap.set('n', 'sf', 'lua require("spectre").open_file_search({select_word=true})', { 105 | desc = "Search on current file" 106 | }) 107 | 108 | wk.register({ 109 | l = { 110 | name = "Lspsaga", 111 | c = { "Lspsaga code_action", "Code Action" }, 112 | o = { "Lspsaga outline", "Outline" }, 113 | r = { "Lspsaga rename", "Rename" }, 114 | d = { "Lspsaga goto_definition", "Lsp GoTo Definition" }, 115 | f = { "Lspsaga finder", "Lsp Finder" }, 116 | p = { "Lspsaga preview_definition", "Preview Definition" }, 117 | s = { "Lspsaga signature_help", "Signature Help" }, 118 | w = { "Lspsaga show_workspace_diagnostics", "Show Workspace Diagnostics" }, 119 | } 120 | }, { prefix = "" }) 121 | 122 | local function visual_cursors_with_delay() 123 | -- Execute the vm-visual-cursors command. 124 | vim.cmd('silent! execute "normal! \\(VM-Visual-Cursors)"') 125 | -- Introduce delay via VimScript's 'sleep' (set to 500 milliseconds here). 126 | vim.cmd('sleep 200m') 127 | -- Press 'A' in normal mode after the delay. 128 | vim.cmd('silent! execute "normal! A"') 129 | end 130 | 131 | wk.register({ 132 | m = { 133 | name = "Visual Multi", 134 | a = { "(VM-Select-All)", "Select All", mode = { "n" } }, 135 | r = { "(VM-Start-Regex-Search)", "Start Regex Search", mode = { "n" } }, 136 | p = { "(VM-Add-Cursor-At-Pos)", "Add Cursor At Pos", mode = { "n" } }, 137 | v = { visual_cursors_with_delay, "Visual Cursors", mode = { "v" } }, 138 | o = { "(VM-Toggle-Mappings)", "Toggle Mapping", mode = { "n" } }, 139 | } 140 | }, { prefix = "" }) 141 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/load.lua: -------------------------------------------------------------------------------- 1 | local packer_load = nil 2 | local cmd = vim.api.nvim_command 3 | local fmt = string.format 4 | 5 | local function verify_conditions(conds, name) 6 | if conds == nil then 7 | return true 8 | end 9 | for _, cond in ipairs(conds) do 10 | local success, result 11 | if type(cond) == 'boolean' then 12 | result = cond 13 | elseif type(cond) == 'string' then 14 | success, result = pcall(loadstring(cond)) 15 | if not success then 16 | vim.schedule(function() 17 | vim.api.nvim_notify( 18 | 'packer.nvim: Error running cond for ' .. name .. ': ' .. result, 19 | vim.log.levels.ERROR, 20 | {} 21 | ) 22 | end) 23 | return false 24 | end 25 | end 26 | if result == false then 27 | return false 28 | end 29 | end 30 | return true 31 | end 32 | 33 | local function loader_clear_loaders(plugin) 34 | if plugin.commands then 35 | for _, del_cmd in ipairs(plugin.commands) do 36 | cmd('silent! delcommand ' .. del_cmd) 37 | end 38 | end 39 | 40 | if plugin.keys then 41 | for _, key in ipairs(plugin.keys) do 42 | cmd(fmt('silent! %sunmap %s', key[1], key[2])) 43 | end 44 | end 45 | end 46 | 47 | local function loader_apply_config(plugin, name) 48 | if plugin.config then 49 | for _, config_line in ipairs(plugin.config) do 50 | local success, err = pcall(loadstring(config_line), name, plugin) 51 | if not success then 52 | vim.schedule(function() 53 | vim.api.nvim_notify('packer.nvim: Error running config for ' .. name .. ': ' .. err, vim.log.levels.ERROR, {}) 54 | end) 55 | end 56 | end 57 | end 58 | end 59 | 60 | local function loader_apply_wants(plugin, plugins) 61 | if plugin.wants then 62 | for _, wanted_name in ipairs(plugin.wants) do 63 | packer_load({ wanted_name }, {}, plugins) 64 | end 65 | end 66 | end 67 | 68 | local function loader_apply_after(plugin, plugins, name) 69 | if plugin.after then 70 | for _, after_name in ipairs(plugin.after) do 71 | local after_plugin = plugins[after_name] 72 | after_plugin.load_after[name] = nil 73 | if next(after_plugin.load_after) == nil then 74 | packer_load({ after_name }, {}, plugins) 75 | end 76 | end 77 | end 78 | end 79 | 80 | local function apply_cause_side_effects(cause) 81 | if cause.cmd then 82 | local lines = cause.l1 == cause.l2 and '' or (cause.l1 .. ',' .. cause.l2) 83 | -- This is a hack to deal with people who haven't recompiled after updating to the new command 84 | -- creation logic 85 | local bang = '' 86 | if type(cause.bang) == 'string' then 87 | bang = cause.bang 88 | elseif type(cause.bang) == 'boolean' and cause.bang then 89 | bang = '!' 90 | end 91 | cmd(fmt('%s %s%s%s %s', cause.mods or '', lines, cause.cmd, bang, cause.args)) 92 | elseif cause.keys then 93 | local extra = '' 94 | while true do 95 | local c = vim.fn.getchar(0) 96 | if c == 0 then 97 | break 98 | end 99 | extra = extra .. vim.fn.nr2char(c) 100 | end 101 | 102 | if cause.prefix then 103 | local prefix = vim.v.count ~= 0 and vim.v.count or '' 104 | prefix = prefix .. '"' .. vim.v.register .. cause.prefix 105 | if vim.fn.mode 'full' == 'no' then 106 | if vim.v.operator == 'c' then 107 | prefix = '' .. prefix 108 | end 109 | prefix = prefix .. vim.v.operator 110 | end 111 | 112 | vim.fn.feedkeys(prefix, 'n') 113 | end 114 | 115 | local escaped_keys = vim.api.nvim_replace_termcodes(cause.keys .. extra, true, true, true) 116 | vim.api.nvim_feedkeys(escaped_keys, 'm', true) 117 | elseif cause.event then 118 | cmd(fmt('doautocmd %s', cause.event)) 119 | elseif cause.ft then 120 | cmd(fmt('doautocmd %s FileType %s', 'filetypeplugin', cause.ft)) 121 | cmd(fmt('doautocmd %s FileType %s', 'filetypeindent', cause.ft)) 122 | cmd(fmt('doautocmd %s FileType %s', 'syntaxset', cause.ft)) 123 | end 124 | end 125 | 126 | packer_load = function(names, cause, plugins, force) 127 | local some_unloaded = false 128 | local needs_bufread = false 129 | local num_names = #names 130 | for i = 1, num_names do 131 | local plugin = plugins[names[i]] 132 | if not plugin then 133 | local err_message = 'Error: attempted to load ' .. names[i] .. ' which is not present in plugins table!' 134 | vim.notify(err_message, vim.log.levels.ERROR, { title = 'packer.nvim' }) 135 | error(err_message) 136 | end 137 | 138 | if not plugin.loaded then 139 | loader_clear_loaders(plugin) 140 | if force or verify_conditions(plugin.cond, names[i]) then 141 | -- Set the plugin as loaded before config is run in case something in the config tries to load 142 | -- this same plugin again 143 | plugin.loaded = true 144 | some_unloaded = true 145 | needs_bufread = needs_bufread or plugin.needs_bufread 146 | loader_apply_wants(plugin, plugins) 147 | cmd('packadd ' .. names[i]) 148 | if plugin.after_files then 149 | for _, file in ipairs(plugin.after_files) do 150 | cmd('silent source ' .. file) 151 | end 152 | end 153 | loader_apply_config(plugin, names[i]) 154 | loader_apply_after(plugin, plugins, names[i]) 155 | end 156 | end 157 | end 158 | 159 | if not some_unloaded then 160 | return 161 | end 162 | 163 | if needs_bufread then 164 | if _G._packer and _G._packer.inside_compile == true then 165 | -- delaying BufRead to end of packer_compiled 166 | _G._packer.needs_bufread = true 167 | else 168 | cmd 'doautocmd BufRead' 169 | end 170 | end 171 | -- Retrigger cmd/keymap... 172 | apply_cause_side_effects(cause) 173 | end 174 | 175 | local function load_wrapper(names, cause, plugins, force) 176 | local success, err_msg = pcall(packer_load, names, cause, plugins, force) 177 | if not success then 178 | vim.cmd 'echohl ErrorMsg' 179 | vim.cmd('echomsg "Error in packer_compiled: ' .. vim.fn.escape(err_msg, '"') .. '"') 180 | vim.cmd 'echomsg "Please check your config for correctness"' 181 | vim.cmd 'echohl None' 182 | end 183 | end 184 | 185 | return load_wrapper 186 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/tests/snapshot_spec.lua: -------------------------------------------------------------------------------- 1 | local before_each = require('plenary.busted').before_each 2 | local a = require 'plenary.async_lib.tests' 3 | local util = require 'packer.util' 4 | local mocked_plugin_utils = require 'packer.plugin_utils' 5 | local log = require 'packer.log' 6 | local async = require('packer.async').sync 7 | local await = require('packer.async').wait 8 | local wait_all = require('packer.async').wait_all 9 | local main = require('packer.async').main 10 | local packer = require 'packer' 11 | local jobs = require 'packer.jobs' 12 | local git = require 'packer.plugin_types.git' 13 | local join_paths = util.join_paths 14 | local stdpath = vim.fn.stdpath 15 | local fmt = string.format 16 | 17 | local config = { 18 | ensure_dependencies = true, 19 | snapshot = nil, 20 | snapshot_path = join_paths(stdpath 'cache', 'packer.nvim'), 21 | package_root = join_paths(stdpath 'data', 'site', 'pack'), 22 | compile_path = join_paths(stdpath 'config', 'plugin', 'packer_compiled.lua'), 23 | plugin_package = 'packer', 24 | max_jobs = nil, 25 | auto_clean = true, 26 | compile_on_sync = true, 27 | disable_commands = false, 28 | opt_default = false, 29 | transitive_opt = true, 30 | transitive_disable = true, 31 | auto_reload_compiled = true, 32 | git = { 33 | mark_breaking_changes = true, 34 | cmd = 'git', 35 | subcommands = { 36 | update = 'pull --ff-only --progress --rebase=false', 37 | install = 'clone --depth %i --no-single-branch --progress', 38 | fetch = 'fetch --depth 999999 --progress', 39 | checkout = 'checkout %s --', 40 | update_branch = 'merge --ff-only @{u}', 41 | current_branch = 'rev-parse --abbrev-ref HEAD', 42 | diff = 'log --color=never --pretty=format:FMT --no-show-signature HEAD@{1}...HEAD', 43 | diff_fmt = '%%h %%s (%%cr)', 44 | git_diff_fmt = 'show --no-color --pretty=medium %s', 45 | get_rev = 'rev-parse --short HEAD', 46 | get_header = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1', 47 | get_bodies = 'log --color=never --pretty=format:"===COMMIT_START===%h%n%s===BODY_START===%b" --no-show-signature HEAD@{1}...HEAD', 48 | submodules = 'submodule update --init --recursive --progress', 49 | revert = 'reset --hard HEAD@{1}', 50 | revert_to = 'reset --hard %s --', 51 | }, 52 | depth = 1, 53 | clone_timeout = 60, 54 | default_url_format = 'https://github.com/%s.git', 55 | }, 56 | display = { 57 | non_interactive = false, 58 | open_fn = nil, 59 | open_cmd = '65vnew', 60 | working_sym = '⟳', 61 | error_sym = '✗', 62 | done_sym = '✓', 63 | removed_sym = '-', 64 | moved_sym = '→', 65 | header_sym = '━', 66 | header_lines = 2, 67 | title = 'packer.nvim', 68 | show_all_info = true, 69 | prompt_border = 'double', 70 | keybindings = { quit = 'q', toggle_info = '', diff = 'd', prompt_revert = 'r' }, 71 | }, 72 | luarocks = { python_cmd = 'python' }, 73 | log = { level = 'trace' }, 74 | profile = { enable = false }, 75 | } 76 | 77 | git.cfg(config) 78 | 79 | --[[ For testing purposes the spec file is made up so that when running `packer` 80 | it could manage itself as if it was in `~/.local/share/nvim/site/pack/packer/start/` --]] 81 | local install_path = vim.fn.getcwd() 82 | 83 | mocked_plugin_utils.list_installed_plugins = function() 84 | return { [install_path] = true }, {} 85 | end 86 | 87 | local old_require = _G.require 88 | 89 | _G.require = function(modname) 90 | if modname == 'plugin_utils' then 91 | return mocked_plugin_utils 92 | end 93 | 94 | return old_require(modname) 95 | end 96 | 97 | local spec = { 'wbthomason/packer.nvim' } 98 | 99 | local function exec_cmd(cmd, opts) 100 | return async(function() 101 | local r = await(jobs.run(cmd, opts)) 102 | if r.err then 103 | print(fmt("Failed on command '%s': %s", cmd, vim.inspect(r.err))) 104 | end 105 | assert.is_not_nil(r.ok) 106 | local _, result = next(r.ok.output.data.stdout) 107 | return result 108 | end) 109 | end 110 | 111 | local snapshotted_plugins = {} 112 | a.describe('Packer testing ', function() 113 | local snapshot_name = 'test' 114 | local test_path = join_paths(config.snapshot_path, snapshot_name) 115 | local snapshot = require 'packer.snapshot' 116 | snapshot.cfg(config) 117 | 118 | before_each(function() 119 | packer.reset() 120 | packer.init(config) 121 | packer.use(spec) 122 | packer.__manage_all() 123 | end) 124 | 125 | after_each(function() 126 | spec = { 'wbthomason/packer.nvim' } 127 | spec.install_path = install_path 128 | end) 129 | 130 | a.describe('snapshot.create()', function() 131 | a.it(fmt("create snapshot in '%s'", test_path), function() 132 | local result = await(snapshot.create(test_path, { spec })) 133 | local stat = vim.loop.fs_stat(test_path) 134 | assert.truthy(stat) 135 | end) 136 | 137 | a.it("checking if snapshot content corresponds to plugins'", function() 138 | async(function() 139 | local file_content = vim.fn.readfile(test_path) 140 | snapshotted_plugins = vim.fn.json_decode(file_content) 141 | local expected_rev = await(spec.get_rev()) 142 | assert.are.equals(expected_rev.ok, snapshotted_plugins['packer.nvim'].commit) 143 | end)() 144 | end) 145 | end) 146 | 147 | a.describe('packer.delete()', function() 148 | a.it(fmt("delete '%s' snapshot", snapshot_name), function() 149 | snapshot.delete(snapshot_name) 150 | local stat = vim.loop.fs_stat(test_path) 151 | assert.falsy(stat) 152 | end) 153 | end) 154 | 155 | a.describe('packer.rollback()', function() 156 | local rollback_snapshot_name = 'rollback_test' 157 | local rollback_test_path = join_paths(config.snapshot_path, rollback_snapshot_name) 158 | local prev_commit_cmd = 'git rev-parse --short HEAD~5' 159 | local get_rev_cmd = 'git rev-parse --short HEAD' 160 | 161 | local opts = { capture_output = true, cwd = spec.install_path, options = { env = git.job_env } } 162 | 163 | a.it("restore 'packer' to the commit hash HEAD~5", function() 164 | async(function() 165 | local commit = await(exec_cmd(prev_commit_cmd, opts)) 166 | snapshotted_plugins['packer.nvim'] = { commit = commit } 167 | await(main) 168 | local encoded_json = vim.fn.json_encode(snapshotted_plugins) 169 | vim.fn.writefile({ encoded_json }, rollback_test_path) 170 | await(snapshot.rollback(rollback_test_path, { spec })) 171 | local rev = await(exec_cmd(get_rev_cmd, opts)) 172 | assert.are.equals(snapshotted_plugins['packer.nvim'].commit, rev) 173 | end)() 174 | end) 175 | end) 176 | end) 177 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/snapshot.lua: -------------------------------------------------------------------------------- 1 | local a = require 'packer.async' 2 | local util = require 'packer.util' 3 | local log = require 'packer.log' 4 | local plugin_utils = require 'packer.plugin_utils' 5 | local plugin_complete = require('packer').plugin_complete 6 | local result = require 'packer.result' 7 | local async = a.sync 8 | local await = a.wait 9 | local fmt = string.format 10 | 11 | local config = {} 12 | 13 | local snapshot = { 14 | completion = {}, 15 | } 16 | 17 | snapshot.cfg = function(_config) 18 | config = _config 19 | end 20 | 21 | --- Completion for listing snapshots in `config.snapshot_path` 22 | --- Intended to provide completion for PackerSnapshotDelete command 23 | snapshot.completion.snapshot = function(lead, cmdline, pos) 24 | local completion_list = {} 25 | if config.snapshot_path == nil then 26 | return completion_list 27 | end 28 | 29 | local dir = vim.loop.fs_opendir(config.snapshot_path) 30 | 31 | if dir ~= nil then 32 | local res = vim.loop.fs_readdir(dir) 33 | while res ~= nil do 34 | for _, entry in ipairs(res) do 35 | if entry.type == 'file' and vim.startswith(entry.name, lead) then 36 | completion_list[#completion_list + 1] = entry.name 37 | end 38 | end 39 | 40 | res = vim.loop.fs_readdir(dir) 41 | end 42 | end 43 | 44 | vim.loop.fs_closedir(dir) 45 | return completion_list 46 | end 47 | 48 | --- Completion for listing single plugins before taking snapshot 49 | --- Intended to provide completion for PackerSnapshot command 50 | snapshot.completion.create = function(lead, cmdline, pos) 51 | local cmd_args = (vim.fn.split(cmdline, ' ')) 52 | 53 | if #cmd_args > 1 then 54 | return plugin_complete(lead, cmdline, pos) 55 | end 56 | 57 | return {} 58 | end 59 | 60 | --- Completion for listing snapshots in `config.snapshot_path` and single plugins after 61 | --- the first argument is provided 62 | --- Intended to provide completion for PackerSnapshotRollback command 63 | snapshot.completion.rollback = function(lead, cmdline, pos) 64 | local cmd_args = vim.split(cmdline, ' ') 65 | 66 | if #cmd_args > 2 then 67 | return plugin_complete(lead) 68 | else 69 | return snapshot.completion.snapshot(lead, cmdline, pos) 70 | end 71 | end 72 | 73 | --- Creates a with with `completed` and `failed` keys, each containing a map with plugin name as key and commit hash/error as value 74 | --- @param plugins list 75 | --- @return { ok: { failed : table, completed : table}} 76 | local function generate_snapshot(plugins) 77 | local completed = {} 78 | local failed = {} 79 | local opt, start = plugin_utils.list_installed_plugins() 80 | local installed = vim.tbl_extend('error', start, opt) 81 | 82 | plugins = vim.tbl_filter(function(plugin) 83 | if installed[plugin.install_path] and plugin.type == plugin_utils.git_plugin_type then -- this plugin is installed 84 | return plugin 85 | end 86 | end, plugins) 87 | return async(function() 88 | for _, plugin in pairs(plugins) do 89 | local rev = await(plugin.get_rev()) 90 | 91 | if rev.err then 92 | failed[plugin.short_name] = 93 | fmt("Snapshotting %s failed because of error '%s'", plugin.short_name, vim.inspect(rev.err)) 94 | else 95 | completed[plugin.short_name] = { commit = rev.ok } 96 | end 97 | end 98 | 99 | return result.ok { failed = failed, completed = completed } 100 | end) 101 | end 102 | 103 | ---Serializes a table of git-plugins with `short_name` as table key and another 104 | ---table with `commit`; the serialized tables will be written in the path `snapshot_path` 105 | ---provided, if there is already a snapshot it will be overwritten 106 | ---Snapshotting work only with `plugin_utils.git_plugin_type` type of plugins, 107 | ---other will be ignored. 108 | ---@param snapshot_path string realpath for snapshot file 109 | ---@param plugins table[] 110 | snapshot.create = function(snapshot_path, plugins) 111 | assert(type(snapshot_path) == 'string', fmt("filename needs to be a string but '%s' provided", type(snapshot_path))) 112 | assert(type(plugins) == 'table', fmt("plugins needs to be an array but '%s' provided", type(plugins))) 113 | return async(function() 114 | local commits = await(generate_snapshot(plugins)) 115 | 116 | await(a.main) 117 | local snapshot_content = vim.fn.json_encode(commits.ok.completed) 118 | 119 | local status, res = pcall(function() 120 | return vim.fn.writefile({ snapshot_content }, snapshot_path) == 0 121 | end) 122 | 123 | if status and res then 124 | return result.ok { 125 | message = fmt("Snapshot '%s' complete", snapshot_path), 126 | completed = commits.ok.completed, 127 | failed = commits.ok.failed, 128 | } 129 | else 130 | return result.err { message = fmt("Error on creation of snapshot '%s': '%s'", snapshot_path, res) } 131 | end 132 | end) 133 | end 134 | 135 | local function fetch(plugin) 136 | local git = require 'packer.plugin_types.git' 137 | local opts = { capture_output = true, cwd = plugin.install_path, options = { env = git.job_env } } 138 | 139 | return async(function() 140 | return await(require('packer.jobs').run('git ' .. config.git.subcommands.fetch, opts)) 141 | end) 142 | end 143 | 144 | ---Rollbacks `plugins` to the hash specified in `snapshot_path` if exists. 145 | ---It automatically runs `git fetch --depth 999999 --progress` to retrieve the history 146 | ---@param snapshot_path string @ realpath to the snapshot file 147 | ---@param plugins list @ of `plugin_utils.git_plugin_type` type of plugins 148 | ---@return {ok: {completed: table, failed: table}} 149 | snapshot.rollback = function(snapshot_path, plugins) 150 | assert(type(snapshot_path) == 'string', 'snapshot_path: expected string but got ' .. type(snapshot_path)) 151 | assert(type(plugins) == 'table', 'plugins: expected table but got ' .. type(snapshot_path)) 152 | log.debug('Rolling back to ' .. snapshot_path) 153 | local content = vim.fn.readfile(snapshot_path) 154 | ---@type string 155 | local plugins_snapshot = vim.fn.json_decode(content) 156 | if plugins_snapshot == nil then -- not valid snapshot file 157 | return result.err(fmt("Couldn't load '%s' file", snapshot_path)) 158 | end 159 | 160 | local completed = {} 161 | local failed = {} 162 | 163 | return async(function() 164 | for _, plugin in pairs(plugins) do 165 | local function err_handler(err) 166 | failed[plugin.short_name] = failed[plugin.short_name] or {} 167 | failed[plugin.short_name][#failed[plugin.short_name] + 1] = err 168 | end 169 | 170 | if plugins_snapshot[plugin.short_name] then 171 | local commit = plugins_snapshot[plugin.short_name].commit 172 | if commit ~= nil then 173 | await(fetch(plugin)) 174 | :map_err(err_handler) 175 | :and_then(await, plugin.revert_to(commit)) 176 | :map_ok(function(ok) 177 | completed[plugin.short_name] = ok 178 | end) 179 | :map_err(err_handler) 180 | end 181 | end 182 | end 183 | 184 | return result.ok { completed = completed, failed = failed } 185 | end) 186 | end 187 | 188 | ---Deletes the snapshot provided 189 | ---@param snapshot_name string absolute path or just a snapshot name 190 | snapshot.delete = function(snapshot_name) 191 | assert(type(snapshot_name) == 'string', fmt('Expected string, got %s', type(snapshot_name))) 192 | ---@type string 193 | local snapshot_path = vim.loop.fs_realpath(snapshot_name) 194 | or vim.loop.fs_realpath(util.join_paths(config.snapshot_path, snapshot_name)) 195 | 196 | if snapshot_path == nil then 197 | local warn = fmt("Snapshot '%s' is wrong or doesn't exist", snapshot_name) 198 | log.warn(warn) 199 | return 200 | end 201 | 202 | log.debug('Deleting ' .. snapshot_path) 203 | if vim.loop.fs_unlink(snapshot_path) then 204 | local info = 'Deleted ' .. snapshot_path 205 | log.info(info) 206 | else 207 | local warn = "Couldn't delete " .. snapshot_path 208 | log.warn(warn) 209 | end 210 | end 211 | 212 | return snapshot 213 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/jobs.lua: -------------------------------------------------------------------------------- 1 | -- Interface with Neovim job control and provide a simple job sequencing structure 2 | local split = vim.split 3 | local loop = vim.loop 4 | local a = require 'packer.async' 5 | local log = require 'packer.log' 6 | local result = require 'packer.result' 7 | 8 | --- Utility function to make a "standard" logging callback for a given set of tables 9 | -- Arguments: 10 | -- - err_tbl: table to which err messages will be logged 11 | -- - data_tbl: table to which data (non-err messages) will be logged 12 | -- - pipe: the pipe for which this callback will be used. Passed in so that we can make sure all 13 | -- output flushes before finishing reading 14 | -- - disp: optional packer.display object for updating task status. Requires `name` 15 | -- - name: optional string name for a current task. Used to update task status 16 | local function make_logging_callback(err_tbl, data_tbl, pipe, disp, name) 17 | return function(err, data) 18 | if err then 19 | table.insert(err_tbl, vim.trim(err)) 20 | end 21 | if data ~= nil then 22 | local trimmed = vim.trim(data) 23 | table.insert(data_tbl, trimmed) 24 | if disp then 25 | disp:task_update(name, split(trimmed, '\n')[1]) 26 | end 27 | else 28 | loop.read_stop(pipe) 29 | loop.close(pipe) 30 | end 31 | end 32 | end 33 | 34 | --- Utility function to make a table for capturing output with "standard" structure 35 | local function make_output_table() 36 | return { err = { stdout = {}, stderr = {} }, data = { stdout = {}, stderr = {} } } 37 | end 38 | 39 | --- Utility function to merge stdout and stderr from two tables with "standard" structure (either 40 | -- the err or data subtables, specifically) 41 | local function extend_output(to, from) 42 | vim.list_extend(to.stdout, from.stdout) 43 | vim.list_extend(to.stderr, from.stderr) 44 | return to 45 | end 46 | 47 | --- Wrapper for vim.loop.spawn. Takes a command, options, and callback just like vim.loop.spawn, but 48 | -- (1) makes an async function and (2) ensures that all output from the command has been flushed 49 | -- before calling the callback 50 | local spawn = a.wrap(function(cmd, options, callback) 51 | local handle = nil 52 | local timer = nil 53 | handle, pid = loop.spawn(cmd, options, function(exit_code, signal) 54 | handle:close() 55 | if timer ~= nil then 56 | timer:stop() 57 | timer:close() 58 | end 59 | 60 | loop.close(options.stdio[1]) 61 | local check = loop.new_check() 62 | loop.check_start(check, function() 63 | for _, pipe in pairs(options.stdio) do 64 | if not loop.is_closing(pipe) then 65 | return 66 | end 67 | end 68 | loop.check_stop(check) 69 | callback(exit_code, signal) 70 | end) 71 | end) 72 | 73 | if options.stdio then 74 | for i, pipe in pairs(options.stdio) do 75 | if options.stdio_callbacks[i] then 76 | loop.read_start(pipe, options.stdio_callbacks[i]) 77 | end 78 | end 79 | end 80 | 81 | if handle == nil then 82 | -- pid is an error string in this case 83 | log.error(string.format("Failed spawning command: %s because %s", cmd, pid)) 84 | callback(-1, pid) 85 | return 86 | end 87 | 88 | if options.timeout then 89 | timer = loop.new_timer() 90 | timer:start(options.timeout, 0, function() 91 | timer:stop() 92 | timer:close() 93 | if loop.is_active(handle) then 94 | log.warn('Killing ' .. cmd .. ' due to timeout!') 95 | loop.process_kill(handle, 'sigint') 96 | handle:close() 97 | for _, pipe in pairs(options.stdio) do 98 | loop.close(pipe) 99 | end 100 | callback(-9999, 'sigint') 101 | end 102 | end) 103 | end 104 | end) 105 | 106 | --- Utility function to perform a common check for process success and return a result object 107 | local function was_successful(r) 108 | if r.exit_code == 0 and (not r.output or not r.output.err or #r.output.err == 0) then 109 | return result.ok(r) 110 | else 111 | return result.err(r) 112 | end 113 | end 114 | 115 | --- Main exposed function for the jobs module. Takes a task and options and returns an async 116 | -- function that will run the task with the given opts via vim.loop.spawn 117 | -- Arguments: 118 | -- - task: either a string or table. If string, split, and the first component is treated as the 119 | -- command. If table, first element is treated as the command. All subsequent elements are passed 120 | -- as args 121 | -- - opts: table of options. Can include the keys "options" (like the options table passed to 122 | -- vim.loop.spawn), "success_test" (a function, called like `was_successful` (above)), 123 | -- "capture_output" (either a boolean, in which case default output capture is set up and the 124 | -- resulting tables are included in the result, or a set of tables, in which case output is logged 125 | -- to the given tables) 126 | local run_job = function(task, opts) 127 | return a.sync(function() 128 | local options = opts.options or { hide = true } 129 | local stdout = nil 130 | local stderr = nil 131 | local job_result = { exit_code = -1, signal = -1 } 132 | local success_test = opts.success_test or was_successful 133 | local uv_err 134 | local output = make_output_table() 135 | local callbacks = {} 136 | local output_valid = false 137 | if opts.capture_output then 138 | if type(opts.capture_output) == 'boolean' then 139 | stdout, uv_err = loop.new_pipe(false) 140 | if uv_err then 141 | log.error('Failed to open stdout pipe: ' .. uv_err) 142 | return result.err() 143 | end 144 | 145 | stderr, uv_err = loop.new_pipe(false) 146 | if uv_err then 147 | log.error('Failed to open stderr pipe: ' .. uv_err) 148 | return job_result 149 | end 150 | 151 | callbacks.stdout = make_logging_callback(output.err.stdout, output.data.stdout, stdout) 152 | callbacks.stderr = make_logging_callback(output.err.stderr, output.data.stderr, stderr) 153 | output_valid = true 154 | elseif type(opts.capture_output) == 'table' then 155 | if opts.capture_output.stdout then 156 | stdout, uv_err = loop.new_pipe(false) 157 | if uv_err then 158 | log.error('Failed to open stdout pipe: ' .. uv_err) 159 | return job_result 160 | end 161 | 162 | callbacks.stdout = function(err, data) 163 | if data ~= nil then 164 | opts.capture_output.stdout(err, data) 165 | else 166 | loop.read_stop(stdout) 167 | loop.close(stdout) 168 | end 169 | end 170 | end 171 | if opts.capture_output.stderr then 172 | stderr, uv_err = loop.new_pipe(false) 173 | if uv_err then 174 | log.error('Failed to open stderr pipe: ' .. uv_err) 175 | return job_result 176 | end 177 | 178 | callbacks.stderr = function(err, data) 179 | if data ~= nil then 180 | opts.capture_output.stderr(err, data) 181 | else 182 | loop.read_stop(stderr) 183 | loop.close(stderr) 184 | end 185 | end 186 | end 187 | end 188 | end 189 | 190 | if type(task) == 'string' then 191 | local split_pattern = '%s+' 192 | task = split(task, split_pattern) 193 | end 194 | 195 | local cmd = task[1] 196 | if opts.timeout then 197 | options.timeout = 1000 * opts.timeout 198 | end 199 | 200 | options.cwd = opts.cwd 201 | 202 | local stdin = loop.new_pipe(false) 203 | options.args = { unpack(task, 2) } 204 | options.stdio = { stdin, stdout, stderr } 205 | options.stdio_callbacks = { nil, callbacks.stdout, callbacks.stderr } 206 | 207 | local exit_code, signal = a.wait(spawn(cmd, options)) 208 | job_result = { exit_code = exit_code, signal = signal } 209 | if output_valid then 210 | job_result.output = output 211 | end 212 | return success_test(job_result) 213 | end) 214 | end 215 | 216 | local jobs = { 217 | run = run_job, 218 | logging_callback = make_logging_callback, 219 | output_table = make_output_table, 220 | extend_output = extend_output, 221 | } 222 | 223 | return jobs 224 | -------------------------------------------------------------------------------- /lua/coc.lua: -------------------------------------------------------------------------------- 1 | -- Some servers have issues with backup files, see #649 2 | vim.opt.backup = false 3 | vim.opt.writebackup = false 4 | 5 | -- Having longer updatetime (default is 4000 ms = 4s) leads to noticeable 6 | -- delays and poor user experience 7 | vim.opt.updatetime = 300 8 | 9 | -- Always show the signcolumn, otherwise it would shift the text each time 10 | -- diagnostics appeared/became resolved 11 | vim.opt.signcolumn = "yes" 12 | 13 | local keyset = vim.keymap.set 14 | -- Autocomplete 15 | function _G.check_back_space() 16 | local col = vim.fn.col('.') - 1 17 | return col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') ~= nil 18 | end 19 | 20 | -- Use Tab for trigger completion with characters ahead and navigate 21 | -- NOTE: There's always a completion item selected by default, you may want to enable 22 | -- no select by setting `"suggest.noselect": true` in your configuration file 23 | -- NOTE: Use command ':verbose imap ' to make sure Tab is not mapped by 24 | -- other plugins before putting this into your config 25 | local opts = {silent = true, noremap = true, expr = true, replace_keycodes = false} 26 | keyset("i", "", 'coc#pum#visible() ? coc#pum#next(1) : v:lua.check_back_space() ? "" : coc#refresh()', opts) 27 | keyset("i", "", [[coc#pum#visible() ? coc#pum#prev(1) : "\"]], opts) 28 | 29 | -- Make to accept selected completion item or notify coc.nvim to format 30 | -- u breaks current undo, please make your own choice 31 | keyset("i", "", [[coc#pum#visible() ? coc#pum#confirm() : "\u\\=coc#on_enter()\"]], opts) 32 | 33 | -- Use to trigger snippets 34 | keyset("i", "", "(coc-snippets-expand-jump)") 35 | -- Use to trigger completion 36 | keyset("i", "", "coc#refresh()", {silent = true, expr = true}) 37 | 38 | -- Use `[g` and `]g` to navigate diagnostics 39 | -- Use `:CocDiagnostics` to get all diagnostics of current buffer in location list 40 | keyset("n", "[g", "(coc-diagnostic-prev)", {silent = true}) 41 | keyset("n", "]g", "(coc-diagnostic-next)", {silent = true}) 42 | 43 | -- GoTo code navigation 44 | keyset("n", "gd", "(coc-definition)", {silent = true}) 45 | keyset("n", "gy", "(coc-type-definition)", {silent = true}) 46 | keyset("n", "gi", "(coc-implementation)", {silent = true}) 47 | keyset("n", "gr", "(coc-references)", {silent = true}) 48 | 49 | 50 | -- Use K to show documentation in preview window 51 | function _G.show_docs() 52 | local cw = vim.fn.expand('') 53 | if vim.fn.index({'vim', 'help'}, vim.bo.filetype) >= 0 then 54 | vim.api.nvim_command('h ' .. cw) 55 | elseif vim.api.nvim_eval('coc#rpc#ready()') then 56 | vim.fn.CocActionAsync('doHover') 57 | else 58 | vim.api.nvim_command('!' .. vim.o.keywordprg .. ' ' .. cw) 59 | end 60 | end 61 | keyset("n", "K", 'lua _G.show_docs()', {silent = true}) 62 | 63 | 64 | -- Highlight the symbol and its references on a CursorHold event(cursor is idle) 65 | vim.api.nvim_create_augroup("CocGroup", {}) 66 | vim.api.nvim_create_autocmd("CursorHold", { 67 | group = "CocGroup", 68 | command = "silent call CocActionAsync('highlight')", 69 | desc = "Highlight symbol under cursor on CursorHold" 70 | }) 71 | 72 | 73 | -- Symbol renaming 74 | keyset("n", "rn", "(coc-rename)", {silent = true}) 75 | 76 | 77 | -- Formatting selected code 78 | keyset("x", "f", "(coc-format-selected)", {silent = true}) 79 | keyset("n", "f", "(coc-format-selected)", {silent = true}) 80 | 81 | 82 | -- Setup formatexpr specified filetype(s) 83 | vim.api.nvim_create_autocmd("FileType", { 84 | group = "CocGroup", 85 | pattern = "typescript,json", 86 | command = "setl formatexpr=CocAction('formatSelected')", 87 | desc = "Setup formatexpr specified filetype(s)." 88 | }) 89 | 90 | -- Update signature help on jump placeholder 91 | vim.api.nvim_create_autocmd("User", { 92 | group = "CocGroup", 93 | pattern = "CocJumpPlaceholder", 94 | command = "call CocActionAsync('showSignatureHelp')", 95 | desc = "Update signature help on jump placeholder" 96 | }) 97 | 98 | -- Apply codeAction to the selected region 99 | -- Example: `aap` for current paragraph 100 | local opts = {silent = true, nowait = true} 101 | keyset("x", "a", "(coc-codeaction-selected)", opts) 102 | keyset("n", "a", "(coc-codeaction-selected)", opts) 103 | 104 | -- Remap keys for apply code actions at the cursor position. 105 | keyset("n", "ac", "(coc-codeaction-cursor)", opts) 106 | -- Remap keys for apply code actions affect whole buffer. 107 | keyset("n", "as", "(coc-codeaction-source)", opts) 108 | -- Remap keys for applying codeActions to the current buffer 109 | keyset("n", "ac", "(coc-codeaction)", opts) 110 | -- Apply the most preferred quickfix action on the current line. 111 | keyset("n", "qf", "(coc-fix-current)", opts) 112 | 113 | -- Remap keys for apply refactor code actions. 114 | keyset("n", "re", "(coc-codeaction-refactor)", { silent = true }) 115 | keyset("x", "r", "(coc-codeaction-refactor-selected)", { silent = true }) 116 | keyset("n", "r", "(coc-codeaction-refactor-selected)", { silent = true }) 117 | 118 | -- Run the Code Lens actions on the current line 119 | keyset("n", "cl", "(coc-codelens-action)", opts) 120 | 121 | 122 | -- Map function and class text objects 123 | -- NOTE: Requires 'textDocument.documentSymbol' support from the language server 124 | keyset("x", "if", "(coc-funcobj-i)", opts) 125 | keyset("o", "if", "(coc-funcobj-i)", opts) 126 | keyset("x", "af", "(coc-funcobj-a)", opts) 127 | keyset("o", "af", "(coc-funcobj-a)", opts) 128 | keyset("x", "ic", "(coc-classobj-i)", opts) 129 | keyset("o", "ic", "(coc-classobj-i)", opts) 130 | keyset("x", "ac", "(coc-classobj-a)", opts) 131 | keyset("o", "ac", "(coc-classobj-a)", opts) 132 | 133 | 134 | -- Remap and to scroll float windows/popups 135 | ---@diagnostic disable-next-line: redefined-local 136 | local opts = {silent = true, nowait = true, expr = true} 137 | keyset("n", "", 'coc#float#has_scroll() ? coc#float#scroll(1) : ""', opts) 138 | keyset("n", "", 'coc#float#has_scroll() ? coc#float#scroll(0) : ""', opts) 139 | keyset("i", "", 140 | 'coc#float#has_scroll() ? "=coc#float#scroll(1)" : ""', opts) 141 | keyset("i", "", 142 | 'coc#float#has_scroll() ? "=coc#float#scroll(0)" : ""', opts) 143 | keyset("v", "", 'coc#float#has_scroll() ? coc#float#scroll(1) : ""', opts) 144 | keyset("v", "", 'coc#float#has_scroll() ? coc#float#scroll(0) : ""', opts) 145 | 146 | 147 | -- Use CTRL-S for selections ranges 148 | -- Requires 'textDocument/selectionRange' support of language server 149 | keyset("n", "", "(coc-range-select)", {silent = true}) 150 | keyset("x", "", "(coc-range-select)", {silent = true}) 151 | 152 | 153 | -- Add `:Format` command to format current buffer 154 | vim.api.nvim_create_user_command("Format", "call CocAction('format')", {}) 155 | 156 | -- " Add `:Fold` command to fold current buffer 157 | vim.api.nvim_create_user_command("Fold", "call CocAction('fold', )", {nargs = '?'}) 158 | 159 | -- Add `:OR` command for organize imports of the current buffer 160 | vim.api.nvim_create_user_command("OR", "call CocActionAsync('runCommand', 'editor.action.organizeImport')", {}) 161 | 162 | -- Add (Neo)Vim's native statusline support 163 | -- NOTE: Please see `:h coc-status` for integrations with external plugins that 164 | -- provide custom statusline: lightline.vim, vim-airline 165 | vim.opt.statusline:prepend("%{coc#status()}%{get(b:,'coc_current_function','')}") 166 | 167 | -- Mappings for CoCList 168 | -- code actions and coc stuff 169 | ---@diagnostic disable-next-line: redefined-local 170 | local opts = {silent = true, nowait = true} 171 | -- Show all diagnostics 172 | keyset("n", "a", ":CocList diagnostics", opts) 173 | -- Manage extensions 174 | keyset("n", "e", ":CocList extensions", opts) 175 | -- Show commands 176 | keyset("n", "c", ":CocList commands", opts) 177 | -- Find symbol of current document 178 | -- Commenting this out because it conflicts with obsidian keymappings. 2023-07-20 08:31 179 | -- keyset("n", "o", ":CocList outline", opts) 180 | -- Search workspace symbols 181 | keyset("n", "s", ":CocList -I symbols", opts) 182 | -- Do default action for next item 183 | keyset("n", "j", ":CocNext", opts) 184 | -- Do default action for previous item 185 | keyset("n", "k", ":CocPrev", opts) 186 | -- Resume latest coc list 187 | keyset("n", "p", ":CocListResume", opts) 188 | -------------------------------------------------------------------------------- /plugin/packer_compiled.lua: -------------------------------------------------------------------------------- 1 | -- Automatically generated packer.nvim plugin loader code 2 | 3 | if vim.api.nvim_call_function('has', {'nvim-0.5'}) ~= 1 then 4 | vim.api.nvim_command('echohl WarningMsg | echom "Invalid Neovim version for packer.nvim! | echohl None"') 5 | return 6 | end 7 | 8 | vim.api.nvim_command('packadd packer.nvim') 9 | 10 | local no_errors, error_msg = pcall(function() 11 | 12 | _G._packer = _G._packer or {} 13 | _G._packer.inside_compile = true 14 | 15 | local time 16 | local profile_info 17 | local should_profile = false 18 | if should_profile then 19 | local hrtime = vim.loop.hrtime 20 | profile_info = {} 21 | time = function(chunk, start) 22 | if start then 23 | profile_info[chunk] = hrtime() 24 | else 25 | profile_info[chunk] = (hrtime() - profile_info[chunk]) / 1e6 26 | end 27 | end 28 | else 29 | time = function(chunk, start) end 30 | end 31 | 32 | local function save_profiles(threshold) 33 | local sorted_times = {} 34 | for chunk_name, time_taken in pairs(profile_info) do 35 | sorted_times[#sorted_times + 1] = {chunk_name, time_taken} 36 | end 37 | table.sort(sorted_times, function(a, b) return a[2] > b[2] end) 38 | local results = {} 39 | for i, elem in ipairs(sorted_times) do 40 | if not threshold or threshold and elem[2] > threshold then 41 | results[i] = elem[1] .. ' took ' .. elem[2] .. 'ms' 42 | end 43 | end 44 | if threshold then 45 | table.insert(results, '(Only showing plugins that took longer than ' .. threshold .. ' ms ' .. 'to load)') 46 | end 47 | 48 | _G._packer.profile_output = results 49 | end 50 | 51 | time([[Luarocks path setup]], true) 52 | local package_path_str = "/root/.cache/nvim/packer_hererocks/2.1.1696795921/share/lua/5.1/?.lua;/root/.cache/nvim/packer_hererocks/2.1.1696795921/share/lua/5.1/?/init.lua;/root/.cache/nvim/packer_hererocks/2.1.1696795921/lib/luarocks/rocks-5.1/?.lua;/root/.cache/nvim/packer_hererocks/2.1.1696795921/lib/luarocks/rocks-5.1/?/init.lua" 53 | local install_cpath_pattern = "/root/.cache/nvim/packer_hererocks/2.1.1696795921/lib/lua/5.1/?.so" 54 | if not string.find(package.path, package_path_str, 1, true) then 55 | package.path = package.path .. ';' .. package_path_str 56 | end 57 | 58 | if not string.find(package.cpath, install_cpath_pattern, 1, true) then 59 | package.cpath = package.cpath .. ';' .. install_cpath_pattern 60 | end 61 | 62 | time([[Luarocks path setup]], false) 63 | time([[try_loadstring definition]], true) 64 | local function try_loadstring(s, component, name) 65 | local success, result = pcall(loadstring(s), name, _G.packer_plugins[name]) 66 | if not success then 67 | vim.schedule(function() 68 | vim.api.nvim_notify('packer.nvim: Error running ' .. component .. ' for ' .. name .. ': ' .. result, vim.log.levels.ERROR, {}) 69 | end) 70 | end 71 | return result 72 | end 73 | 74 | time([[try_loadstring definition]], false) 75 | time([[Defining packer_plugins]], true) 76 | _G.packer_plugins = { 77 | ["Comment.nvim"] = { 78 | loaded = true, 79 | path = "/root/.local/share/nvim/site/pack/packer/start/Comment.nvim", 80 | url = "https://github.com/numToStr/Comment.nvim" 81 | }, 82 | ["bufferline.nvim"] = { 83 | loaded = true, 84 | path = "/root/.local/share/nvim/site/pack/packer/start/bufferline.nvim", 85 | url = "https://github.com/akinsho/bufferline.nvim" 86 | }, 87 | ["cmp-buffer"] = { 88 | loaded = true, 89 | path = "/root/.local/share/nvim/site/pack/packer/start/cmp-buffer", 90 | url = "https://github.com/hrsh7th/cmp-buffer" 91 | }, 92 | ["cmp-cmdline"] = { 93 | loaded = true, 94 | path = "/root/.local/share/nvim/site/pack/packer/start/cmp-cmdline", 95 | url = "https://github.com/hrsh7th/cmp-cmdline" 96 | }, 97 | ["cmp-path"] = { 98 | loaded = true, 99 | path = "/root/.local/share/nvim/site/pack/packer/start/cmp-path", 100 | url = "https://github.com/hrsh7th/cmp-path" 101 | }, 102 | ["cmp-vsnip"] = { 103 | loaded = true, 104 | path = "/root/.local/share/nvim/site/pack/packer/start/cmp-vsnip", 105 | url = "https://github.com/hrsh7th/cmp-vsnip" 106 | }, 107 | ["coc.nvim"] = { 108 | loaded = true, 109 | path = "/root/.local/share/nvim/site/pack/packer/start/coc.nvim", 110 | url = "https://github.com/neoclide/coc.nvim" 111 | }, 112 | ["diffview.nvim"] = { 113 | config = { "\27LJ\2\n6\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\rdiffview\frequire\0" }, 114 | loaded = true, 115 | path = "/root/.local/share/nvim/site/pack/packer/start/diffview.nvim", 116 | url = "https://github.com/sindrets/diffview.nvim" 117 | }, 118 | everforest = { 119 | loaded = true, 120 | path = "/root/.local/share/nvim/site/pack/packer/start/everforest", 121 | url = "https://github.com/sainnhe/everforest" 122 | }, 123 | ["flash.nvim"] = { 124 | loaded = true, 125 | path = "/root/.local/share/nvim/site/pack/packer/start/flash.nvim", 126 | url = "https://github.com/folke/flash.nvim" 127 | }, 128 | ["friendly-snippets"] = { 129 | loaded = true, 130 | path = "/root/.local/share/nvim/site/pack/packer/start/friendly-snippets", 131 | url = "https://github.com/rafamadriz/friendly-snippets" 132 | }, 133 | harpoon = { 134 | loaded = true, 135 | path = "/root/.local/share/nvim/site/pack/packer/start/harpoon", 136 | url = "https://github.com/ThePrimeagen/harpoon" 137 | }, 138 | ["indent-blankline.nvim"] = { 139 | loaded = true, 140 | path = "/root/.local/share/nvim/site/pack/packer/start/indent-blankline.nvim", 141 | url = "https://github.com/lukas-reineke/indent-blankline.nvim" 142 | }, 143 | ["lualine.nvim"] = { 144 | loaded = true, 145 | path = "/root/.local/share/nvim/site/pack/packer/start/lualine.nvim", 146 | url = "https://github.com/nvim-lualine/lualine.nvim" 147 | }, 148 | neogit = { 149 | config = { "\27LJ\2\n4\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\vneogit\frequire\0" }, 150 | loaded = true, 151 | path = "/root/.local/share/nvim/site/pack/packer/start/neogit", 152 | url = "https://github.com/treatybreaker/neogit" 153 | }, 154 | ["nvim-cmp"] = { 155 | loaded = true, 156 | path = "/root/.local/share/nvim/site/pack/packer/start/nvim-cmp", 157 | url = "https://github.com/hrsh7th/nvim-cmp" 158 | }, 159 | ["nvim-tree.lua"] = { 160 | loaded = true, 161 | path = "/root/.local/share/nvim/site/pack/packer/start/nvim-tree.lua", 162 | url = "https://github.com/nvim-tree/nvim-tree.lua" 163 | }, 164 | ["nvim-treesitter"] = { 165 | loaded = true, 166 | path = "/root/.local/share/nvim/site/pack/packer/start/nvim-treesitter", 167 | url = "https://github.com/nvim-treesitter/nvim-treesitter" 168 | }, 169 | ["nvim-ufo"] = { 170 | loaded = true, 171 | path = "/root/.local/share/nvim/site/pack/packer/start/nvim-ufo", 172 | url = "https://github.com/kevinhwang91/nvim-ufo" 173 | }, 174 | ["nvim-web-devicons"] = { 175 | loaded = false, 176 | needs_bufread = false, 177 | path = "/root/.local/share/nvim/site/pack/packer/opt/nvim-web-devicons", 178 | url = "https://github.com/nvim-tree/nvim-web-devicons" 179 | }, 180 | ["packer.nvim"] = { 181 | loaded = false, 182 | needs_bufread = false, 183 | path = "/root/.local/share/nvim/site/pack/packer/opt/packer.nvim", 184 | url = "https://github.com/wbthomason/packer.nvim" 185 | }, 186 | ["plenary.nvim"] = { 187 | loaded = true, 188 | path = "/root/.local/share/nvim/site/pack/packer/start/plenary.nvim", 189 | url = "https://github.com/nvim-lua/plenary.nvim" 190 | }, 191 | ["promise-async"] = { 192 | loaded = true, 193 | path = "/root/.local/share/nvim/site/pack/packer/start/promise-async", 194 | url = "https://github.com/kevinhwang91/promise-async" 195 | }, 196 | ["telescope.nvim"] = { 197 | loaded = true, 198 | path = "/root/.local/share/nvim/site/pack/packer/start/telescope.nvim", 199 | url = "https://github.com/nvim-telescope/telescope.nvim" 200 | }, 201 | ["toggleterm.nvim"] = { 202 | config = { "\27LJ\2\n|\0\0\4\0\a\0\v6\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\3\0006\3\4\0009\3\5\0039\3\6\3=\3\6\2B\0\2\1K\0\1\0\nshell\6o\bvim\1\0\3\tsize\3\20\14autochdir\2\18close_on_exit\1\nsetup\15toggleterm\frequire\0" }, 203 | loaded = true, 204 | path = "/root/.local/share/nvim/site/pack/packer/start/toggleterm.nvim", 205 | url = "https://github.com/akinsho/toggleterm.nvim" 206 | }, 207 | treesj = { 208 | loaded = true, 209 | path = "/root/.local/share/nvim/site/pack/packer/start/treesj", 210 | url = "https://github.com/Wansmer/treesj" 211 | }, 212 | ["vim-surround"] = { 213 | loaded = true, 214 | path = "/root/.local/share/nvim/site/pack/packer/start/vim-surround", 215 | url = "https://github.com/tpope/vim-surround" 216 | }, 217 | ["vim-vsnip"] = { 218 | loaded = true, 219 | path = "/root/.local/share/nvim/site/pack/packer/start/vim-vsnip", 220 | url = "https://github.com/hrsh7th/vim-vsnip" 221 | }, 222 | ["which-key.nvim"] = { 223 | loaded = true, 224 | path = "/root/.local/share/nvim/site/pack/packer/start/which-key.nvim", 225 | url = "https://github.com/folke/which-key.nvim" 226 | } 227 | } 228 | 229 | time([[Defining packer_plugins]], false) 230 | -- Config for: neogit 231 | time([[Config for neogit]], true) 232 | try_loadstring("\27LJ\2\n4\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\vneogit\frequire\0", "config", "neogit") 233 | time([[Config for neogit]], false) 234 | -- Config for: toggleterm.nvim 235 | time([[Config for toggleterm.nvim]], true) 236 | try_loadstring("\27LJ\2\n|\0\0\4\0\a\0\v6\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\3\0006\3\4\0009\3\5\0039\3\6\3=\3\6\2B\0\2\1K\0\1\0\nshell\6o\bvim\1\0\3\tsize\3\20\14autochdir\2\18close_on_exit\1\nsetup\15toggleterm\frequire\0", "config", "toggleterm.nvim") 237 | time([[Config for toggleterm.nvim]], false) 238 | -- Config for: diffview.nvim 239 | time([[Config for diffview.nvim]], true) 240 | try_loadstring("\27LJ\2\n6\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\rdiffview\frequire\0", "config", "diffview.nvim") 241 | time([[Config for diffview.nvim]], false) 242 | 243 | _G._packer.inside_compile = false 244 | if _G._packer.needs_bufread == true then 245 | vim.cmd("doautocmd BufRead") 246 | end 247 | _G._packer.needs_bufread = false 248 | 249 | if should_profile then save_profiles() end 250 | 251 | end) 252 | 253 | if not no_errors then 254 | error_msg = error_msg:gsub('"', '\\"') 255 | vim.api.nvim_command('echohl ErrorMsg | echom "Error in packer_compiled: '..error_msg..'" | echom "Please check your config for correctness" | echohl None') 256 | end 257 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/plugin_utils.lua: -------------------------------------------------------------------------------- 1 | local a = require 'packer.async' 2 | local jobs = require 'packer.jobs' 3 | local util = require 'packer.util' 4 | local result = require 'packer.result' 5 | local log = require 'packer.log' 6 | 7 | local await = a.wait 8 | 9 | local config = nil 10 | local plugin_utils = {} 11 | plugin_utils.cfg = function(_config) 12 | config = _config 13 | end 14 | 15 | plugin_utils.custom_plugin_type = 'custom' 16 | plugin_utils.local_plugin_type = 'local' 17 | plugin_utils.git_plugin_type = 'git' 18 | 19 | plugin_utils.guess_type = function(plugin) 20 | if plugin.installer then 21 | plugin.type = plugin_utils.custom_plugin_type 22 | elseif vim.fn.isdirectory(plugin.path) ~= 0 then 23 | plugin.url = plugin.path 24 | plugin.type = plugin_utils.local_plugin_type 25 | elseif 26 | string.sub(plugin.path, 1, 6) == 'git://' 27 | or string.sub(plugin.path, 1, 4) == 'http' 28 | or string.match(plugin.path, '@') 29 | then 30 | plugin.url = plugin.path 31 | plugin.type = plugin_utils.git_plugin_type 32 | else 33 | local path = table.concat(vim.split(plugin.path, '\\', true), '/') 34 | plugin.url = string.format(config.git.default_url_format, path) 35 | plugin.type = plugin_utils.git_plugin_type 36 | end 37 | end 38 | 39 | plugin_utils.guess_dir_type = function(dir) 40 | local globdir = vim.fn.glob(dir) 41 | local dir_type = (vim.loop.fs_lstat(globdir) or { type = 'noexist' }).type 42 | 43 | --[[ NOTE: We're assuming here that: 44 | 1. users only create custom plugins for non-git repos; 45 | 2. custom plugins don't use symlinks to install; 46 | otherwise, there's no consistent way to tell from a dir alone… ]] 47 | if dir_type == 'link' then 48 | return plugin_utils.local_plugin_type 49 | elseif vim.loop.fs_stat(globdir .. '/.git') then 50 | return plugin_utils.git_plugin_type 51 | elseif dir_type ~= 'noexist' then 52 | return plugin_utils.custom_plugin_type 53 | end 54 | end 55 | 56 | plugin_utils.helptags_stale = function(dir) 57 | -- Adapted directly from minpac.vim 58 | local txts = vim.fn.glob(util.join_paths(dir, '*.txt'), true, true) 59 | vim.list_extend(txts, vim.fn.glob(util.join_paths(dir, '*.[a-z][a-z]x'), true, true)) 60 | local tags = vim.fn.glob(util.join_paths(dir, 'tags'), true, true) 61 | vim.list_extend(tags, vim.fn.glob(util.join_paths(dir, 'tags-[a-z][a-z]'), true, true)) 62 | local txt_ftimes = util.map(vim.fn.getftime, txts) 63 | local tag_ftimes = util.map(vim.fn.getftime, tags) 64 | if #txt_ftimes == 0 then 65 | return false 66 | end 67 | if #tag_ftimes == 0 then 68 | return true 69 | end 70 | local txt_newest = math.max(unpack(txt_ftimes)) 71 | local tag_oldest = math.min(unpack(tag_ftimes)) 72 | return txt_newest > tag_oldest 73 | end 74 | 75 | plugin_utils.update_helptags = vim.schedule_wrap(function(...) 76 | for _, dir in ipairs(...) do 77 | local doc_dir = util.join_paths(dir, 'doc') 78 | if plugin_utils.helptags_stale(doc_dir) then 79 | log.info('Updating helptags for ' .. doc_dir) 80 | vim.cmd('silent! helptags ' .. vim.fn.fnameescape(doc_dir)) 81 | end 82 | end 83 | end) 84 | 85 | plugin_utils.update_rplugins = vim.schedule_wrap(function() 86 | if vim.fn.exists ':UpdateRemotePlugins' == 2 then 87 | vim.cmd [[silent UpdateRemotePlugins]] 88 | end 89 | end) 90 | 91 | plugin_utils.ensure_dirs = function() 92 | if vim.fn.isdirectory(config.opt_dir) == 0 then 93 | vim.fn.mkdir(config.opt_dir, 'p') 94 | end 95 | 96 | if vim.fn.isdirectory(config.start_dir) == 0 then 97 | vim.fn.mkdir(config.start_dir, 'p') 98 | end 99 | end 100 | 101 | plugin_utils.list_installed_plugins = function() 102 | local opt_plugins = {} 103 | local start_plugins = {} 104 | local opt_dir_handle = vim.loop.fs_opendir(config.opt_dir, nil, 50) 105 | if opt_dir_handle then 106 | local opt_dir_items = vim.loop.fs_readdir(opt_dir_handle) 107 | while opt_dir_items do 108 | for _, item in ipairs(opt_dir_items) do 109 | opt_plugins[util.join_paths(config.opt_dir, item.name)] = true 110 | end 111 | 112 | opt_dir_items = vim.loop.fs_readdir(opt_dir_handle) 113 | end 114 | end 115 | 116 | local start_dir_handle = vim.loop.fs_opendir(config.start_dir, nil, 50) 117 | if start_dir_handle then 118 | local start_dir_items = vim.loop.fs_readdir(start_dir_handle) 119 | while start_dir_items do 120 | for _, item in ipairs(start_dir_items) do 121 | start_plugins[util.join_paths(config.start_dir, item.name)] = true 122 | end 123 | 124 | start_dir_items = vim.loop.fs_readdir(start_dir_handle) 125 | end 126 | end 127 | 128 | return opt_plugins, start_plugins 129 | end 130 | 131 | plugin_utils.find_missing_plugins = function(plugins, opt_plugins, start_plugins) 132 | return a.sync(function() 133 | if opt_plugins == nil or start_plugins == nil then 134 | opt_plugins, start_plugins = plugin_utils.list_installed_plugins() 135 | end 136 | 137 | -- NOTE/TODO: In the case of a plugin gaining/losing an alias, this will force a clean and 138 | -- reinstall 139 | local missing_plugins = {} 140 | for _, plugin_name in ipairs(vim.tbl_keys(plugins)) do 141 | local plugin = plugins[plugin_name] 142 | if not plugin.disable then 143 | local plugin_path = util.join_paths(config[plugin.opt and 'opt_dir' or 'start_dir'], plugin.short_name) 144 | local plugin_installed = (plugin.opt and opt_plugins or start_plugins)[plugin_path] 145 | 146 | await(a.main) 147 | local guessed_type = plugin_utils.guess_dir_type(plugin_path) 148 | if not plugin_installed or plugin.type ~= guessed_type then 149 | missing_plugins[plugin_name] = true 150 | elseif guessed_type == plugin_utils.git_plugin_type then 151 | local r = await(plugin.remote_url()) 152 | local remote = r.ok and r.ok.remote or nil 153 | if remote then 154 | -- Form a Github-style user/repo string 155 | local parts = vim.split(remote, '[:/]') 156 | local repo_name = parts[#parts - 1] .. '/' .. parts[#parts] 157 | repo_name = repo_name:gsub('%.git', '') 158 | 159 | -- Also need to test for "full URL" plugin names, but normalized to get rid of the 160 | -- protocol 161 | local normalized_remote = remote:gsub('https://', ''):gsub('ssh://git@', '') 162 | local normalized_plugin_name = plugin.name:gsub('https://', ''):gsub('ssh://git@', ''):gsub('\\', '/') 163 | if (normalized_remote ~= normalized_plugin_name) and (repo_name ~= normalized_plugin_name) then 164 | missing_plugins[plugin_name] = true 165 | end 166 | end 167 | end 168 | end 169 | end 170 | 171 | return missing_plugins 172 | end) 173 | end 174 | 175 | plugin_utils.get_fs_state = function(plugins) 176 | log.debug 'Updating FS state' 177 | local opt_plugins, start_plugins = plugin_utils.list_installed_plugins() 178 | return a.sync(function() 179 | local missing_plugins = await(plugin_utils.find_missing_plugins(plugins, opt_plugins, start_plugins)) 180 | return { opt = opt_plugins, start = start_plugins, missing = missing_plugins } 181 | end) 182 | end 183 | 184 | plugin_utils.load_plugin = function(plugin) 185 | if plugin.opt then 186 | vim.cmd('packadd ' .. plugin.short_name) 187 | else 188 | vim.o.runtimepath = vim.o.runtimepath .. ',' .. plugin.install_path 189 | for _, pat in ipairs { 190 | table.concat({ 'plugin', '**/*.vim' }, util.get_separator()), 191 | table.concat({ 'after', 'plugin', '**/*.vim' }, util.get_separator()), 192 | } do 193 | local path = util.join_paths(plugin.install_path, pat) 194 | local glob_ok, files = pcall(vim.fn.glob, path, false, true) 195 | if not glob_ok then 196 | if string.find(files, 'E77') then 197 | vim.cmd('silent exe "source ' .. path .. '"') 198 | else 199 | error(files) 200 | end 201 | elseif #files > 0 then 202 | for _, file in ipairs(files) do 203 | file = file:gsub('\\', '/') 204 | vim.cmd('silent exe "source ' .. file .. '"') 205 | end 206 | end 207 | end 208 | end 209 | end 210 | 211 | plugin_utils.post_update_hook = function(plugin, disp) 212 | local plugin_name = util.get_plugin_full_name(plugin) 213 | return a.sync(function() 214 | if plugin.run or not plugin.opt then 215 | await(a.main) 216 | plugin_utils.load_plugin(plugin) 217 | end 218 | 219 | if plugin.run then 220 | if type(plugin.run) ~= 'table' then 221 | plugin.run = { plugin.run } 222 | end 223 | disp:task_update(plugin_name, 'running post update hooks...') 224 | local hook_result = result.ok() 225 | for _, task in ipairs(plugin.run) do 226 | if type(task) == 'function' then 227 | local success, err = pcall(task, plugin, disp) 228 | if not success then 229 | return result.err { 230 | msg = 'Error running post update hook: ' .. vim.inspect(err), 231 | } 232 | end 233 | elseif type(task) == 'string' then 234 | if string.sub(task, 1, 1) == ':' then 235 | await(a.main) 236 | vim.cmd(string.sub(task, 2)) 237 | else 238 | local hook_output = { err = {}, output = {} } 239 | local hook_callbacks = { 240 | stderr = jobs.logging_callback(hook_output.err, hook_output.output, nil, disp, plugin_name), 241 | stdout = jobs.logging_callback(hook_output.err, hook_output.output, nil, disp, plugin_name), 242 | } 243 | local cmd 244 | local shell = os.getenv 'SHELL' or vim.o.shell 245 | if shell:find 'cmd.exe$' then 246 | cmd = { shell, '/c', task } 247 | else 248 | cmd = { shell, '-c', task } 249 | end 250 | hook_result = await(jobs.run(cmd, { capture_output = hook_callbacks, cwd = plugin.install_path })):map_err( 251 | function(err) 252 | return { 253 | msg = string.format('Error running post update hook: %s', table.concat(hook_output.output, '\n')), 254 | data = err, 255 | } 256 | end 257 | ) 258 | 259 | if hook_result.err then 260 | return hook_result 261 | end 262 | end 263 | else 264 | -- TODO/NOTE: This case should also capture output in case of error. The minor difficulty is 265 | -- what to do if the plugin's run table (i.e. this case) already specifies output handling. 266 | 267 | hook_result = await(jobs.run(task)):map_err(function(err) 268 | return { 269 | msg = string.format('Error running post update hook: %s', vim.inspect(err)), 270 | data = err, 271 | } 272 | end) 273 | 274 | if hook_result.err then 275 | return hook_result 276 | end 277 | end 278 | end 279 | 280 | return hook_result 281 | else 282 | return result.ok() 283 | end 284 | end) 285 | end 286 | 287 | return plugin_utils 288 | -------------------------------------------------------------------------------- /lua/pluginconfigs.lua: -------------------------------------------------------------------------------- 1 | require("toggleterm").setup { 2 | close_on_exit = false, 3 | autochdir = 'true', 4 | shell = vim.o.shell, 5 | size = 20 6 | } 7 | 8 | require('nvim-tree').setup({ 9 | filters = { dotfiles = false, git_ignored = false }, 10 | auto_reload_on_write = true, 11 | view = { 12 | centralize_selection = false, 13 | cursorline = true, 14 | debounce_delay = 15, 15 | width = {}, 16 | side = "left", 17 | preserve_window_proportions = false, 18 | number = true, 19 | relativenumber = true, 20 | signcolumn = "yes", 21 | }, 22 | update_focused_file = { enable = true, update_root = false, ignore_list = {} }, 23 | renderer = { 24 | add_trailing = false, 25 | group_empty = false, 26 | highlight_git = false, 27 | full_name = false, 28 | highlight_opened_files = "all", 29 | highlight_modified = "none", 30 | root_folder_label = ":~:s?$?/..?", 31 | indent_width = 2, 32 | indent_markers = { 33 | enable = true, 34 | inline_arrows = true, 35 | icons = { 36 | corner = "└", 37 | edge = "│", 38 | item = "│", 39 | bottom = "─", 40 | none = " ", 41 | }, 42 | }, 43 | } 44 | }) 45 | 46 | require('ufo').setup() 47 | 48 | 49 | require 'nvim-treesitter.configs'.setup { 50 | -- A list of parser names, or 51 | -- "all" (the five listed parsers 52 | -- should always be installed) 53 | ensure_installed = { 54 | "bash", 55 | "fish", 56 | "lua", 57 | "markdown", 58 | "vim", 59 | "regex", 60 | "markdown_inline", 61 | }, 62 | 63 | -- Install parsers synchronously 64 | -- (only applied to 65 | -- `ensure_installed`) 66 | sync_install = false, 67 | 68 | -- Automatically install missing 69 | -- parsers when entering buffer 70 | -- Recommendation: set to false 71 | -- if you don't have `tree-sitter` 72 | -- CLI installed locally 73 | auto_install = false, 74 | } 75 | 76 | -- indent blankline 77 | require("indent_blankline").setup { 78 | show_current_context = true, 79 | show_current_context_start = true, 80 | show_end_of_line = true, 81 | } 82 | 83 | 84 | -- treesj 85 | require('treesj').setup({ 86 | -- Use default keymaps 87 | -- (m - toggle, j - join, s - split) 88 | use_default_keymaps = false, 89 | 90 | -- Node with syntax error will not be formatted 91 | check_syntax_error = false, 92 | 93 | -- If line after join will be longer than max value, 94 | -- node will not be formatted 95 | max_join_length = 120, 96 | 97 | -- hold|start|end: 98 | -- hold - cursor follows the node/place on which it was called 99 | -- start - cursor jumps to the first symbol of the node being formatted 100 | -- end - cursor jumps to the last symbol of the node being formatted 101 | cursor_behavior = 'hold', 102 | 103 | -- Notify about possible problems or not 104 | notify = true, 105 | langs = { 106 | lua = require('treesj.langs.lua'), 107 | typescript = require('treesj.langs.typescript'), 108 | }, 109 | 110 | -- Use `dot` for repeat action 111 | dot_repeat = true, 112 | }) 113 | 114 | require('Comment').setup() 115 | 116 | require('telescope').setup({ 117 | pickers = { 118 | find_files = { 119 | theme = "dropdown", 120 | }, 121 | live_grep = { 122 | theme = "dropdown", 123 | }, 124 | help_tags = { 125 | theme = "dropdown", 126 | } 127 | } 128 | }) 129 | 130 | -- lualine 131 | local colors = { 132 | blue = '#80a0ff', 133 | cyan = '#79dac8', 134 | black = '#080808', 135 | white = '#c6c6c6', 136 | red = '#ff5189', 137 | violet = '#d183e8', 138 | grey = '#303030', 139 | } 140 | local bubbles_theme = { 141 | normal = { 142 | a = { fg = colors.black, bg = colors.violet }, 143 | b = { fg = colors.white, bg = colors.grey }, 144 | c = { fg = colors.black, bg = colors.black }, 145 | }, 146 | 147 | insert = { a = { fg = colors.black, bg = colors.blue } }, 148 | visual = { a = { fg = colors.black, bg = colors.cyan } }, 149 | replace = { a = { fg = colors.black, bg = colors.red } }, 150 | 151 | inactive = { 152 | a = { fg = colors.white, bg = colors.black }, 153 | b = { fg = colors.white, bg = colors.black }, 154 | c = { fg = colors.black, bg = colors.black }, 155 | }, 156 | } 157 | require('lualine').setup({ 158 | options = { 159 | theme = bubbles_theme, 160 | component_separators = '|', 161 | section_separators = { left = '', right = '' }, 162 | }, 163 | sections = { 164 | lualine_a = { 165 | { 'mode', separator = { left = '' }, right_padding = 2 }, 166 | }, 167 | lualine_b = { 'filename', 'branch' }, 168 | lualine_c = { 'fileformat' }, 169 | lualine_x = {}, 170 | lualine_y = { 'filetype', 'progress' }, 171 | lualine_z = { 172 | { 'location', separator = { right = '' }, left_padding = 2 }, 173 | }, 174 | }, 175 | inactive_sections = { 176 | lualine_a = { 'filename' }, 177 | lualine_b = {}, 178 | lualine_c = {}, 179 | lualine_x = {}, 180 | lualine_y = {}, 181 | lualine_z = { 'location' }, 182 | }, 183 | tabline = {}, 184 | extensions = {}, 185 | }) 186 | 187 | -- Harpoon 188 | require('harpoon').setup({ 189 | global_settings = { 190 | -- sets the marks upon calling `toggle` on the ui, instead of require `:w`. 191 | save_on_toggle = false, 192 | 193 | -- saves the harpoon file upon every change. disabling is unrecommended. 194 | save_on_change = true, 195 | 196 | -- sets harpoon to run the command immediately as it's passed to the terminal when calling `sendCommand`. 197 | enter_on_sendcmd = false, 198 | 199 | -- closes any tmux windows harpoon that harpoon creates when you close Neovim. 200 | tmux_autoclose_windows = false, 201 | 202 | -- filetypes that you want to prevent from adding to the harpoon list menu. 203 | excluded_filetypes = { "harpoon" }, 204 | 205 | -- set marks specific to each git branch inside git repository 206 | -- Each branch will have it's own set of marked files 207 | mark_branch = true, 208 | 209 | -- enable tabline with harpoon marks 210 | tabline = false, 211 | tabline_prefix = " ", 212 | tabline_suffix = " ", 213 | } 214 | }) 215 | 216 | -- Harpoon telescope extension 217 | require('telescope').load_extension('harpoon') 218 | 219 | -- Bufferline 220 | require("bufferline").setup { 221 | options = { 222 | mode = 'buffers', 223 | -- diagnostics = 'coc', 224 | offsets = { 225 | { 226 | filetype = "NvimTree", 227 | text = "File Explorer", 228 | highlight = "Directory", 229 | separator = true, 230 | } 231 | }, 232 | }, 233 | } 234 | 235 | -- which-key 236 | require("which-key").setup { 237 | plugins = { 238 | marks = true, -- shows a list of your marks on ' and ` 239 | registers = true, -- shows your registers on " in NORMAL or in INSERT mode 240 | -- the presets plugin, adds help for a bunch of default keybindings in Neovim 241 | -- No actual key bindings are created 242 | spelling = { 243 | enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions 244 | suggestions = 20, -- how many suggestions should be shown in the list? 245 | }, 246 | presets = { 247 | operators = true, -- adds help for operators like d, y, ... 248 | motions = true, -- adds help for motions 249 | text_objects = true, -- help for text objects triggered after entering an operator 250 | windows = true, -- default bindings on 251 | nav = true, -- misc bindings to work with windows 252 | z = true, -- bindings for folds, spelling and others prefixed with z 253 | g = true, -- bindings for prefixed with g 254 | }, 255 | }, 256 | operators = { gc = "Comments" }, 257 | icons = { 258 | breadcrumb = "»", -- symbol used in the command line area that shows your active key combo 259 | separator = "➜", -- symbol used between a key and it's label 260 | group = "+", -- symbol prepended to a group 261 | }, 262 | popup_mappings = { 263 | scroll_down = "", -- binding to scroll down inside the popup 264 | scroll_up = "", -- binding to scroll up inside the popup 265 | }, 266 | window = { 267 | border = "none", -- none, single, double, shadow 268 | position = "bottom", -- bottom, top 269 | margin = { 1, 0, 1, 0 }, -- extra window margin [top, right, bottom, left]. When between 0 and 1, will be treated as a percentage of the screen size. 270 | padding = { 1, 2, 1, 2 }, -- extra window padding [top, right, bottom, left] 271 | winblend = 0, -- value between 0-100 0 for fully opaque and 100 for fully transparent 272 | zindex = 1000, -- positive value to position WhichKey above other floating windows. 273 | }, 274 | } 275 | 276 | require("flash").setup({}) 277 | 278 | 279 | --nvim-cmp 280 | local has_words_before = function() 281 | unpack = unpack or table.unpack 282 | local line, col = unpack(vim.api.nvim_win_get_cursor(0)) 283 | return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil 284 | end 285 | 286 | local feedkey = function(key, mode) 287 | vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true) 288 | end 289 | 290 | local cmp = require('cmp') 291 | cmp.setup({ 292 | snippet = { 293 | -- REQUIRED - you must specify a snippet engine 294 | expand = function(args) 295 | vim.fn["vsnip#anonymous"](args.body) 296 | end, 297 | }, 298 | window = { 299 | completion = cmp.config.window.bordered(), 300 | documentation = cmp.config.window.bordered(), 301 | }, 302 | mapping = cmp.mapping.preset.insert({ 303 | [''] = cmp.mapping.scroll_docs(-4), 304 | [''] = cmp.mapping.scroll_docs(4), 305 | [''] = cmp.mapping.complete(), 306 | [''] = cmp.mapping.abort(), 307 | [''] = cmp.mapping.confirm({ select = false }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. 308 | -- Super-Tab like mappings 309 | -- https://github.com/hrsh7th/nvim-cmp/wiki/Example-mappings#vim-vsnip 310 | [""] = cmp.mapping(function(fallback) 311 | if cmp.visible() then 312 | cmp.select_next_item() 313 | elseif vim.fn["vsnip#available"](1) == 1 then 314 | feedkey("(vsnip-expand-or-jump)", "") 315 | elseif has_words_before() then 316 | cmp.complete() 317 | else 318 | fallback() -- The fallback function sends a already mapped key. In this case, it's probably ``. 319 | end 320 | end, { "i", "s" }), 321 | 322 | [""] = cmp.mapping(function() 323 | if cmp.visible() then 324 | cmp.select_prev_item() 325 | elseif vim.fn["vsnip#jumpable"](-1) == 1 then 326 | feedkey("(vsnip-jump-prev)", "") 327 | end 328 | end, { "i", "s" }), 329 | 330 | }), 331 | sources = cmp.config.sources({ 332 | { name = 'vsnip' }, -- For ultisnips users. 333 | { name = 'nvim_lsp' }, 334 | }, { 335 | { name = 'buffer' }, 336 | }) 337 | }) 338 | -- 339 | -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). 340 | cmp.setup.cmdline({ '/', '?' }, { 341 | mapping = cmp.mapping.preset.cmdline(), 342 | sources = { 343 | { name = 'buffer' } 344 | } 345 | }) 346 | -- 347 | -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). 348 | cmp.setup.cmdline(':', { 349 | mapping = cmp.mapping.preset.cmdline(), 350 | sources = cmp.config.sources({ 351 | { name = 'path' } 352 | }, { 353 | { name = 'cmdline' } 354 | }) 355 | }) 356 | 357 | -- gp 358 | require('gp').setup({ 359 | openai_api_key = os.getenv("OPENAI_API_KEY"), 360 | }) 361 | -- lsp config 362 | -- 363 | -- This is what we had before. 364 | -- require'lspconfig'.lua_ls.setup{} 365 | 366 | -- We are replacing that with: 367 | -- 368 | require('mason').setup() 369 | require('mason-lspconfig').setup() 370 | require("mason-lspconfig").setup_handlers { 371 | -- The first entry (without a key) will be the default handler 372 | -- and will be called for each installed server that doesn't have 373 | -- a dedicated handler. 374 | function(server_name) -- default handler (optional) 375 | require("lspconfig")[server_name].setup {} 376 | end, 377 | } 378 | 379 | require('lspmappings') 380 | 381 | require('spectre').setup({ 382 | result_padding = '', 383 | default = { 384 | replace = { 385 | cmd = "sed" 386 | } 387 | } 388 | }) 389 | 390 | require('gitsigns').setup({}) 391 | vim.cmd "set statusline+=%{get(b:,'gitsigns_status','')}" 392 | 393 | require('lspsaga').setup({ 394 | lightbulb = { 395 | enable = false, 396 | }, 397 | }) 398 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/luarocks.lua: -------------------------------------------------------------------------------- 1 | -- Add support for installing and cleaning Luarocks dependencies 2 | -- Based off of plenary/neorocks/init.lua in https://github.com/nvim-lua/plenary.nvim 3 | local a = require 'packer.async' 4 | local jobs = require 'packer.jobs' 5 | local log = require 'packer.log' 6 | local result = require 'packer.result' 7 | local util = require 'packer.util' 8 | 9 | local fmt = string.format 10 | local async = a.sync 11 | local await = a.wait 12 | 13 | local config = nil 14 | local function cfg(_config) 15 | config = _config.luarocks 16 | end 17 | local function warn_need_luajit() 18 | log.error 'LuaJIT is required for Luarocks functionality!' 19 | end 20 | 21 | local lua_version = nil 22 | if jit then 23 | local jit_version = string.gsub(jit.version, 'LuaJIT ', '') 24 | lua_version = { lua = string.gsub(_VERSION, 'Lua ', ''), jit = jit_version, dir = jit_version } 25 | else 26 | return { 27 | handle_command = warn_need_luajit, 28 | install_commands = warn_need_luajit, 29 | list = warn_need_luajit, 30 | install_hererocks = warn_need_luajit, 31 | setup_paths = warn_need_luajit, 32 | uninstall = warn_need_luajit, 33 | clean = warn_need_luajit, 34 | install = warn_need_luajit, 35 | ensure = warn_need_luajit, 36 | generate_path_setup = function() 37 | return '' 38 | end, 39 | cfg = cfg, 40 | } 41 | end 42 | 43 | local cache_path = vim.fn.stdpath 'cache' 44 | local rocks_path = util.join_paths(cache_path, 'packer_hererocks') 45 | local hererocks_file = util.join_paths(rocks_path, 'hererocks.py') 46 | local hererocks_install_dir = util.join_paths(rocks_path, lua_version.dir) 47 | local shell_hererocks_dir = vim.fn.shellescape(hererocks_install_dir) 48 | local _hererocks_setup_done = false 49 | local function hererocks_is_setup() 50 | if _hererocks_setup_done then 51 | return true 52 | end 53 | local path_info = vim.loop.fs_stat(util.join_paths(hererocks_install_dir, 'lib')) 54 | _hererocks_setup_done = (path_info ~= nil) and (path_info['type'] == 'directory') 55 | return _hererocks_setup_done 56 | end 57 | 58 | local function hererocks_installer(disp) 59 | return async(function() 60 | local hererocks_url = 'https://raw.githubusercontent.com/luarocks/hererocks/master/hererocks.py' 61 | local hererocks_cmd 62 | await(a.main) 63 | vim.fn.mkdir(rocks_path, 'p') 64 | if vim.fn.executable 'curl' > 0 then 65 | hererocks_cmd = 'curl ' .. hererocks_url .. ' -o ' .. hererocks_file 66 | elseif vim.fn.executable 'wget' > 0 then 67 | hererocks_cmd = 'wget ' .. hererocks_url .. ' -O ' .. hererocks_file .. ' --verbose' 68 | else 69 | return result.err '"curl" or "wget" is required to install hererocks' 70 | end 71 | 72 | if disp ~= nil then 73 | disp:task_start('luarocks-hererocks', 'installing hererocks...') 74 | end 75 | local output = jobs.output_table() 76 | local callbacks = { 77 | stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, 'luarocks-hererocks'), 78 | stderr = jobs.logging_callback(output.err.stderr, output.data.stderr), 79 | } 80 | 81 | local opts = { capture_output = callbacks } 82 | local r = await(jobs.run(hererocks_cmd, opts)):map_err(function(err) 83 | return { msg = 'Error installing hererocks', data = err, output = output } 84 | end) 85 | 86 | local luarocks_cmd = config.python_cmd 87 | .. ' ' 88 | .. hererocks_file 89 | .. ' --verbose -j ' 90 | .. lua_version.jit 91 | .. ' -r latest ' 92 | .. hererocks_install_dir 93 | r:and_then(await, jobs.run(luarocks_cmd, opts)) 94 | :map_ok(function() 95 | if disp then 96 | disp:task_succeeded('luarocks-hererocks', 'installed hererocks!') 97 | end 98 | end) 99 | :map_err(function(err) 100 | if disp then 101 | disp:task_failed('luarocks-hererocks', 'failed to install hererocks!') 102 | end 103 | log.error('Failed to install hererocks: ' .. vim.inspect(err)) 104 | return { msg = 'Error installing luarocks', data = err, output = output } 105 | end) 106 | return r 107 | end) 108 | end 109 | 110 | local function package_patterns(dir) 111 | local sep = util.get_separator() 112 | return fmt('%s%s?.lua;%s%s?%sinit.lua', dir, sep, dir, sep, sep) 113 | end 114 | 115 | local package_paths = (function() 116 | local install_path = util.join_paths(hererocks_install_dir, 'lib', 'luarocks', fmt('rocks-%s', lua_version.lua)) 117 | local share_path = util.join_paths(hererocks_install_dir, 'share', 'lua', lua_version.lua) 118 | return package_patterns(share_path) .. ';' .. package_patterns(install_path) 119 | end)() 120 | 121 | local nvim_paths_are_setup = false 122 | local function setup_nvim_paths() 123 | if not hererocks_is_setup() then 124 | log.warn 'Tried to setup Neovim Lua paths before hererocks was setup!' 125 | return 126 | end 127 | 128 | if nvim_paths_are_setup then 129 | log.warn 'Tried to setup Neovim Lua paths redundantly!' 130 | return 131 | end 132 | 133 | if not string.find(package.path, package_paths, 1, true) then 134 | package.path = package.path .. ';' .. package_paths 135 | end 136 | 137 | local install_cpath = util.join_paths(hererocks_install_dir, 'lib', 'lua', lua_version.lua) 138 | local install_cpath_pattern = fmt('%s%s?.so', install_cpath, util.get_separator()) 139 | if not string.find(package.cpath, install_cpath_pattern, 1, true) then 140 | package.cpath = package.cpath .. ';' .. install_cpath_pattern 141 | end 142 | 143 | nvim_paths_are_setup = true 144 | end 145 | 146 | local function generate_path_setup_code() 147 | local package_path_str = vim.inspect(package_paths) 148 | local install_cpath = util.join_paths(hererocks_install_dir, 'lib', 'lua', lua_version.lua) 149 | local install_cpath_pattern = fmt('"%s%s?.so"', install_cpath, util.get_separator()) 150 | install_cpath_pattern = vim.fn.escape(install_cpath_pattern, [[\]]) 151 | return [[ 152 | local package_path_str = ]] .. package_path_str .. [[ 153 | 154 | local install_cpath_pattern = ]] .. install_cpath_pattern .. [[ 155 | 156 | if not string.find(package.path, package_path_str, 1, true) then 157 | package.path = package.path .. ';' .. package_path_str 158 | end 159 | 160 | if not string.find(package.cpath, install_cpath_pattern, 1, true) then 161 | package.cpath = package.cpath .. ';' .. install_cpath_pattern 162 | end 163 | ]] 164 | end 165 | 166 | local function activate_hererocks_cmd(install_path) 167 | local activate_file = 'activate' 168 | local user_shell = os.getenv 'SHELL' 169 | local shell = user_shell:gmatch '([^/]*)$'() 170 | if shell == 'fish' then 171 | activate_file = 'activate.fish' 172 | elseif shell == 'csh' then 173 | activate_file = 'activate.csh' 174 | end 175 | 176 | return fmt('source %s', util.join_paths(install_path, 'bin', activate_file)) 177 | end 178 | 179 | local function run_luarocks(args, disp, operation_name) 180 | local cmd = { 181 | os.getenv 'SHELL', 182 | '-c', 183 | fmt('%s && luarocks --tree=%s %s', activate_hererocks_cmd(hererocks_install_dir), shell_hererocks_dir, args), 184 | } 185 | return async(function() 186 | local output = jobs.output_table() 187 | local callbacks = { 188 | stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, operation_name), 189 | stderr = jobs.logging_callback(output.err.stderr, output.data.stderr), 190 | } 191 | 192 | local opts = { capture_output = callbacks } 193 | return await(jobs.run(cmd, opts)) 194 | :map_err(function(err) 195 | return { msg = fmt('Error running luarocks %s', args), data = err, output = output } 196 | end) 197 | :map_ok(function(data) 198 | return { data = data, output = output } 199 | end) 200 | end) 201 | end 202 | 203 | local luarocks_keys = { only_server = 'only-server', only_source = 'only-sources' } 204 | 205 | local function is_valid_luarock_key(key) 206 | return not (key == 'tree' or key == 'local') 207 | end 208 | 209 | local function format_luarocks_args(package) 210 | if type(package) ~= 'table' then 211 | return '' 212 | end 213 | local args = {} 214 | for key, value in pairs(package) do 215 | if type(key) == 'string' and is_valid_luarock_key(key) then 216 | local luarock_key = luarocks_keys[key] and luarocks_keys[key] or key 217 | if luarock_key and type(value) == 'string' then 218 | table.insert(args, string.format('--%s=%s', key, value)) 219 | elseif key == 'env' and type(value) == 'table' then 220 | for name, env_value in pairs(value) do 221 | table.insert(args, string.format('%s=%s', name, env_value)) 222 | end 223 | end 224 | end 225 | end 226 | return ' ' .. table.concat(args, ' ') 227 | end 228 | 229 | local function luarocks_install(package, results, disp) 230 | return async(function() 231 | local package_name = type(package) == 'table' and package[1] or package 232 | if disp then 233 | disp:task_update('luarocks-install', 'installing ' .. package_name) 234 | end 235 | local args = format_luarocks_args(package) 236 | local version = package.version and ' ' .. package.version .. ' ' or '' 237 | local install_result = await(run_luarocks('install ' .. package_name .. version .. args, disp, 'luarocks-install')) 238 | if results then 239 | results.luarocks.installs[package_name] = install_result 240 | end 241 | return install_result 242 | end) 243 | end 244 | 245 | local function install_packages(packages, results, disp) 246 | return async(function() 247 | local r = result.ok() 248 | if not hererocks_is_setup() then 249 | r:and_then(await, hererocks_installer(disp)) 250 | end 251 | if disp then 252 | disp:task_start('luarocks-install', 'installing rocks...') 253 | end 254 | if results then 255 | results.luarocks.installs = {} 256 | end 257 | for _, package in ipairs(packages) do 258 | r:and_then(await, luarocks_install(package, results, disp)) 259 | end 260 | r:map_ok(function() 261 | if disp then 262 | disp:task_succeeded('luarocks-install', 'rocks installed!') 263 | end 264 | end):map_err(function() 265 | if disp then 266 | disp:task_failed('luarocks-install', 'installing rocks failed!') 267 | end 268 | end) 269 | return r 270 | end) 271 | end 272 | 273 | --- Install the packages specified with `packages` synchronously 274 | local function install_sync(packages) 275 | return async(function() 276 | return await(install_packages(packages)) 277 | end)() 278 | end 279 | 280 | local function chunk_output(output) 281 | -- Merge the output to a single line, then split again. Helps to deal with inconsistent 282 | -- chunking in the output collection 283 | local res = table.concat(output, '\n') 284 | return vim.split(res, '\n') 285 | end 286 | 287 | local function luarocks_list(disp) 288 | return async(function() 289 | local r = result.ok() 290 | if not hererocks_is_setup() then 291 | r:and_then(await, hererocks_installer(disp)) 292 | end 293 | r:and_then(await, run_luarocks 'list --porcelain') 294 | return r:map_ok(function(data) 295 | local results = {} 296 | local output = chunk_output(data.output.data.stdout) 297 | for _, line in ipairs(output) do 298 | for l_package, version, status, install_path in string.gmatch(line, '([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)') do 299 | table.insert(results, { 300 | name = l_package, 301 | version = version, 302 | status = status, 303 | install_path = install_path, 304 | }) 305 | end 306 | end 307 | 308 | return results 309 | end) 310 | end) 311 | end 312 | 313 | local function luarocks_show(package, disp) 314 | return async(function() 315 | local r = result.ok() 316 | if not hererocks_is_setup() then 317 | r:and_then(await, hererocks_installer(disp)) 318 | end 319 | r:and_then(await, run_luarocks('show --porcelain ' .. package)) 320 | return r:map_ok(function(data) 321 | local output = chunk_output(data.output.data.stdout) 322 | local dependencies = {} 323 | for _, line in ipairs(output) do 324 | local components = {} 325 | for component in string.gmatch(line, '([^%s]+)') do 326 | components[#components + 1] = component 327 | end 328 | 329 | if (components[1] == 'dependency' or components[1] == 'indirect_dependency') and (components[2] ~= 'lua') then 330 | dependencies[components[2]] = components[2] 331 | end 332 | end 333 | 334 | return dependencies 335 | end) 336 | end) 337 | end 338 | 339 | local function luarocks_remove(package, results, disp) 340 | return async(function() 341 | if disp then 342 | disp:task_update('luarocks-remove', 'removing ' .. package) 343 | end 344 | local remove_result = await(run_luarocks('remove ' .. package, disp, 'luarocks-remove')) 345 | if results then 346 | results.luarocks.removals[package] = remove_result 347 | end 348 | return remove_result 349 | end) 350 | end 351 | 352 | local function uninstall_packages(packages, results, disp) 353 | return async(function() 354 | local r = result.ok() 355 | if not hererocks_is_setup() then 356 | r:and_then(await, hererocks_installer(disp)) 357 | end 358 | if disp then 359 | disp:task_start('luarocks-remove', 'uninstalling rocks...') 360 | end 361 | if results then 362 | results.luarocks.removals = {} 363 | end 364 | for _, package in ipairs(packages) do 365 | local name = type(package) == 'table' and package[1] or package 366 | r:and_then(await, luarocks_remove(name, results, disp)) 367 | end 368 | r:map_ok(function() 369 | if disp then 370 | disp:task_succeeded('luarocks-remove', 'rocks cleaned!') 371 | end 372 | end):map_err(function() 373 | if disp then 374 | disp:task_failed('luarocks-remove', 'cleaning rocks failed!') 375 | end 376 | end) 377 | return r 378 | end) 379 | end 380 | 381 | --- Uninstall the packages specified with `packages` synchronously 382 | local function uninstall_sync(packages) 383 | return async(function() 384 | return await(uninstall_packages(packages)) 385 | end)() 386 | end 387 | 388 | local function clean_rocks(rocks, results, disp) 389 | return async(function() 390 | local r = result.ok() 391 | if not hererocks_is_setup() then 392 | return r 393 | end 394 | r:and_then(await, luarocks_list(disp)) 395 | local installed_packages 396 | if r.ok then 397 | installed_packages = r.ok 398 | else 399 | return r 400 | end 401 | 402 | local dependency_info = {} 403 | for _, package in ipairs(installed_packages) do 404 | r:and_then(await, luarocks_show(package.name, disp)) 405 | if r.ok then 406 | dependency_info[package.name] = r.ok 407 | end 408 | end 409 | 410 | r = r:map_ok(function() 411 | local to_remove = {} 412 | for _, package in ipairs(installed_packages) do 413 | to_remove[package.name] = package 414 | end 415 | for _, rock in pairs(rocks) do 416 | if type(rock) == 'table' then 417 | if to_remove[rock[1]] and (not rock.version or to_remove[rock[1]].version == rock.version) then 418 | to_remove[rock[1]] = nil 419 | end 420 | else 421 | to_remove[rock] = nil 422 | end 423 | end 424 | 425 | for rock, dependencies in pairs(dependency_info) do 426 | if rocks[rock] ~= nil then 427 | for _, dependency in pairs(dependencies) do 428 | to_remove[dependency] = nil 429 | end 430 | end 431 | end 432 | 433 | -- Toposort to ensure that we remove packages before their dependencies 434 | local removal_order = {} 435 | local frontier = {} 436 | for rock, _ in pairs(to_remove) do 437 | if next(dependency_info[rock]) == nil then 438 | frontier[#frontier + 1] = rock 439 | dependency_info[rock] = nil 440 | end 441 | end 442 | 443 | local inverse_dependencies = {} 444 | for rock, depends in pairs(dependency_info) do 445 | for d, _ in pairs(depends) do 446 | inverse_dependencies[d] = inverse_dependencies[d] or {} 447 | inverse_dependencies[d][rock] = true 448 | end 449 | end 450 | 451 | while #frontier > 0 do 452 | local rock = table.remove(frontier) 453 | removal_order[#removal_order + 1] = rock 454 | local inv_depends = inverse_dependencies[rock] 455 | if inv_depends ~= nil then 456 | for depends, _ in pairs(inverse_dependencies[rock]) do 457 | table.remove(dependency_info[depends]) 458 | if #dependency_info[depends] == 0 then 459 | frontier[#frontier + 1] = depends 460 | end 461 | end 462 | end 463 | end 464 | 465 | local reverse_order = {} 466 | for i = #removal_order, 1, -1 do 467 | reverse_order[#reverse_order + 1] = removal_order[i] 468 | end 469 | return reverse_order 470 | end) 471 | 472 | if results ~= nil then 473 | results.luarocks = results.luarocks or {} 474 | end 475 | return r:and_then(await, uninstall_packages(r.ok, results, disp)) 476 | end) 477 | end 478 | 479 | local function ensure_rocks(rocks, results, disp) 480 | return async(function() 481 | local to_install = {} 482 | for _, rock in pairs(rocks) do 483 | if type(rock) == 'table' then 484 | to_install[rock[1]:lower()] = rock 485 | else 486 | to_install[rock:lower()] = true 487 | end 488 | end 489 | 490 | local r = result.ok() 491 | if next(to_install) == nil then 492 | return r 493 | end 494 | if disp == nil then 495 | disp = require('packer.display').open(config.display.open_fn or config.display.open_cmd) 496 | end 497 | if not hererocks_is_setup() then 498 | r = r:and_then(await, hererocks_installer(disp)) 499 | end 500 | r:and_then(await, luarocks_list(disp)) 501 | r:map_ok(function(installed_packages) 502 | for _, package in ipairs(installed_packages) do 503 | local spec = to_install[package.name] 504 | if spec then 505 | if type(spec) == 'table' then 506 | -- if the package is on the system and the spec has no version 507 | -- or it has a version and that is the version on the system do not install it again 508 | if not spec.version or (spec.version and spec.version == package.version) then 509 | to_install[package.name] = nil 510 | end 511 | else 512 | to_install[package.name] = nil 513 | end 514 | end 515 | end 516 | 517 | local package_specs = {} 518 | for name, spec in pairs(to_install) do 519 | if type(spec) == 'table' then 520 | table.insert(package_specs, spec) 521 | else 522 | table.insert(package_specs, { name }) 523 | end 524 | end 525 | 526 | return package_specs 527 | end) 528 | 529 | results.luarocks = results.luarocks or {} 530 | return r:and_then(await, install_packages(r.ok, results, disp)) 531 | end) 532 | end 533 | 534 | local function handle_command(cmd, ...) 535 | local task 536 | local packages = { ... } 537 | if cmd == 'install' then 538 | task = install_packages(packages) 539 | elseif cmd == 'remove' then 540 | task = uninstall_packages(packages) 541 | else 542 | log.warn 'Unrecognized command!' 543 | return result.err 'Unrecognized command' 544 | end 545 | 546 | return async(function() 547 | local r = await(task) 548 | await(a.main) 549 | local package_names = vim.fn.escape(vim.inspect(packages), '"') 550 | return r:map_ok(function(data) 551 | local operation_name = cmd:sub(1, 1):upper() .. cmd:sub(2) 552 | log.info(fmt('%sed packages %s', operation_name, package_names)) 553 | return data 554 | end):map_err(function(err) 555 | log.error(fmt('Failed to %s packages %s: %s', cmd, package_names, vim.fn.escape(vim.inspect(err), '"\n'))) 556 | return err 557 | end) 558 | end)() 559 | end 560 | 561 | local function make_commands() 562 | vim.cmd [[ command! -nargs=+ PackerRocks lua require('packer.luarocks').handle_command() ]] 563 | end 564 | 565 | return { 566 | handle_command = handle_command, 567 | install_commands = make_commands, 568 | list = luarocks_list, 569 | install_hererocks = hererocks_installer, 570 | setup_paths = setup_nvim_paths, 571 | uninstall = uninstall_sync, 572 | clean = clean_rocks, 573 | install = install_sync, 574 | ensure = ensure_rocks, 575 | generate_path_setup = generate_path_setup_code, 576 | cfg = cfg, 577 | } 578 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/plugin_types/git.lua: -------------------------------------------------------------------------------- 1 | local util = require 'packer.util' 2 | local jobs = require 'packer.jobs' 3 | local a = require 'packer.async' 4 | local result = require 'packer.result' 5 | local log = require 'packer.log' 6 | local await = a.wait 7 | local async = a.sync 8 | local fmt = string.format 9 | 10 | local vim = vim 11 | 12 | local git = {} 13 | 14 | local blocked_env_vars = { 15 | GIT_DIR = true, 16 | GIT_INDEX_FILE = true, 17 | GIT_OBJECT_DIRECTORY = true, 18 | GIT_TERMINAL_PROMPT = true, 19 | GIT_WORK_TREE = true, 20 | GIT_COMMON_DIR = true, 21 | } 22 | 23 | local function ensure_git_env() 24 | if git.job_env == nil then 25 | local job_env = {} 26 | for k, v in pairs(vim.fn.environ()) do 27 | if not blocked_env_vars[k] then 28 | table.insert(job_env, k .. '=' .. v) 29 | end 30 | end 31 | 32 | table.insert(job_env, 'GIT_TERMINAL_PROMPT=0') 33 | git.job_env = job_env 34 | end 35 | end 36 | 37 | local function has_wildcard(tag) 38 | if not tag then 39 | return false 40 | end 41 | return string.match(tag, '*') ~= nil 42 | end 43 | 44 | local break_tag_pattern = [=[[bB][rR][eE][aA][kK]!?:]=] 45 | local breaking_change_pattern = [=[[bB][rR][eE][aA][kK][iI][nN][gG][ _][cC][hH][aA][nN][gG][eE]]=] 46 | local type_exclam_pattern = [=[[a-zA-Z]+!:]=] 47 | local type_scope_exclam_pattern = [=[[a-zA-Z]+%([^)]+%)!:]=] 48 | local function mark_breaking_commits(plugin, commit_bodies) 49 | local commits = vim.gsplit(table.concat(commit_bodies, '\n'), '===COMMIT_START===', true) 50 | for commit in commits do 51 | local commit_parts = vim.split(commit, '===BODY_START===') 52 | local body = commit_parts[2] 53 | local lines = vim.split(commit_parts[1], '\n') 54 | local is_breaking = ( 55 | body ~= nil 56 | and ( 57 | (string.match(body, breaking_change_pattern) ~= nil) 58 | or (string.match(body, break_tag_pattern) ~= nil) 59 | or (string.match(body, type_exclam_pattern) ~= nil) 60 | or (string.match(body, type_scope_exclam_pattern) ~= nil) 61 | ) 62 | ) 63 | or ( 64 | lines[2] ~= nil 65 | and ( 66 | (string.match(lines[2], breaking_change_pattern) ~= nil) 67 | or (string.match(lines[2], break_tag_pattern) ~= nil) 68 | or (string.match(lines[2], type_exclam_pattern) ~= nil) 69 | or (string.match(lines[2], type_scope_exclam_pattern) ~= nil) 70 | ) 71 | ) 72 | if is_breaking then 73 | plugin.breaking_commits[#plugin.breaking_commits + 1] = lines[1] 74 | end 75 | end 76 | end 77 | 78 | local config = nil 79 | git.cfg = function(_config) 80 | config = _config.git 81 | config.base_dir = _config.package_root 82 | config.default_base_dir = util.join_paths(config.base_dir, _config.plugin_package) 83 | config.exec_cmd = config.cmd .. ' ' 84 | ensure_git_env() 85 | end 86 | 87 | ---Resets a git repo `dest` to `commit` 88 | ---@param dest string @ path to the local git repo 89 | ---@param commit string @ commit hash 90 | ---@return function @ async function 91 | local function reset(dest, commit) 92 | local reset_cmd = fmt(config.exec_cmd .. config.subcommands.revert_to, commit) 93 | local opts = { capture_output = true, cwd = dest, options = { env = git.job_env } } 94 | return async(function() 95 | return await(jobs.run(reset_cmd, opts)) 96 | end) 97 | end 98 | 99 | local handle_checkouts = function(plugin, dest, disp, opts) 100 | local plugin_name = util.get_plugin_full_name(plugin) 101 | return async(function() 102 | if disp ~= nil then 103 | disp:task_update(plugin_name, 'fetching reference...') 104 | end 105 | local output = jobs.output_table() 106 | local callbacks = { 107 | stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, plugin_name), 108 | stderr = jobs.logging_callback(output.err.stderr, output.data.stderr), 109 | } 110 | 111 | local job_opts = { capture_output = callbacks, cwd = dest, options = { env = git.job_env } } 112 | 113 | local r = result.ok() 114 | 115 | if plugin.tag and has_wildcard(plugin.tag) then 116 | disp:task_update(plugin_name, fmt('getting tag for wildcard %s...', plugin.tag)) 117 | local fetch_tags = config.exec_cmd .. fmt(config.subcommands.tags_expand_fmt, plugin.tag) 118 | r:and_then(await, jobs.run(fetch_tags, job_opts)) 119 | local data = output.data.stdout[1] 120 | if data then 121 | plugin.tag = vim.split(data, '\n')[1] 122 | else 123 | log.warn( 124 | fmt('Wildcard expansion did not found any tag for plugin %s: defaulting to latest commit...', plugin.name) 125 | ) 126 | plugin.tag = nil -- Wildcard is not found, then we bypass the tag 127 | end 128 | end 129 | 130 | if plugin.branch or (plugin.tag and not opts.preview_updates) then 131 | local branch_or_tag = plugin.branch and plugin.branch or plugin.tag 132 | if disp ~= nil then 133 | disp:task_update(plugin_name, fmt('checking out %s %s...', plugin.branch and 'branch' or 'tag', branch_or_tag)) 134 | end 135 | r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, branch_or_tag), job_opts)) 136 | :map_err(function(err) 137 | return { 138 | msg = fmt( 139 | 'Error checking out %s %s for %s', 140 | plugin.branch and 'branch' or 'tag', 141 | branch_or_tag, 142 | plugin_name 143 | ), 144 | data = err, 145 | output = output, 146 | } 147 | end) 148 | end 149 | 150 | if plugin.commit then 151 | if disp ~= nil then 152 | disp:task_update(plugin_name, fmt('checking out %s...', plugin.commit)) 153 | end 154 | r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, plugin.commit), job_opts)) 155 | :map_err(function(err) 156 | return { 157 | msg = fmt('Error checking out commit %s for %s', plugin.commit, plugin_name), 158 | data = err, 159 | output = output, 160 | } 161 | end) 162 | end 163 | 164 | return r:map_ok(function(ok) 165 | return { status = ok, output = output } 166 | end):map_err(function(err) 167 | if not err.msg then 168 | return { 169 | msg = fmt('Error updating %s: %s', plugin_name, table.concat(err, '\n')), 170 | data = err, 171 | output = output, 172 | } 173 | end 174 | 175 | err.output = output 176 | return err 177 | end) 178 | end) 179 | end 180 | 181 | local get_rev = function(plugin) 182 | local plugin_name = util.get_plugin_full_name(plugin) 183 | 184 | local rev_cmd = config.exec_cmd .. config.subcommands.get_rev 185 | 186 | return async(function() 187 | local rev = await(jobs.run(rev_cmd, { cwd = plugin.install_path, options = { env = git.job_env }, capture_output = true })) 188 | :map_ok(function(ok) 189 | local _, r = next(ok.output.data.stdout) 190 | return r 191 | end) 192 | :map_err(function(err) 193 | local _, msg = fmt('%s: %s', plugin_name, next(err.output.data.stderr)) 194 | return msg 195 | end) 196 | 197 | return rev 198 | end) 199 | end 200 | 201 | local split_messages = function(messages) 202 | local lines = {} 203 | for _, message in ipairs(messages) do 204 | vim.list_extend(lines, vim.split(message, '\n')) 205 | table.insert(lines, '') 206 | end 207 | return lines 208 | end 209 | 210 | git.setup = function(plugin) 211 | local plugin_name = util.get_plugin_full_name(plugin) 212 | local install_to = plugin.install_path 213 | local install_cmd = 214 | vim.split(config.exec_cmd .. fmt(config.subcommands.install, plugin.commit and 999999 or config.depth), '%s+') 215 | 216 | local submodule_cmd = config.exec_cmd .. config.subcommands.submodules 217 | local rev_cmd = config.exec_cmd .. config.subcommands.get_rev 218 | local update_cmd = config.exec_cmd .. config.subcommands.update 219 | local update_head_cmd = config.exec_cmd .. config.subcommands.update_head 220 | local fetch_cmd = config.exec_cmd .. config.subcommands.fetch 221 | if plugin.commit or plugin.tag then 222 | update_cmd = fetch_cmd 223 | end 224 | 225 | local branch_cmd = config.exec_cmd .. config.subcommands.current_branch 226 | local current_commit_cmd = vim.split(config.exec_cmd .. config.subcommands.get_header, '%s+') 227 | for i, arg in ipairs(current_commit_cmd) do 228 | current_commit_cmd[i] = string.gsub(arg, 'FMT', config.subcommands.diff_fmt) 229 | end 230 | 231 | if plugin.branch or (plugin.tag and not has_wildcard(plugin.tag)) then 232 | install_cmd[#install_cmd + 1] = '--branch' 233 | install_cmd[#install_cmd + 1] = plugin.branch and plugin.branch or plugin.tag 234 | end 235 | 236 | install_cmd[#install_cmd + 1] = plugin.url 237 | install_cmd[#install_cmd + 1] = install_to 238 | 239 | local needs_checkout = plugin.tag ~= nil or plugin.commit ~= nil or plugin.branch ~= nil 240 | 241 | plugin.installer = function(disp) 242 | local output = jobs.output_table() 243 | local callbacks = { 244 | stdout = jobs.logging_callback(output.err.stdout, output.data.stdout), 245 | stderr = jobs.logging_callback(output.err.stderr, output.data.stderr, nil, disp, plugin_name), 246 | } 247 | 248 | local installer_opts = { 249 | capture_output = callbacks, 250 | timeout = config.clone_timeout, 251 | options = { env = git.job_env }, 252 | } 253 | 254 | return async(function() 255 | disp:task_update(plugin_name, 'cloning...') 256 | local r = await(jobs.run(install_cmd, installer_opts)) 257 | 258 | installer_opts.cwd = install_to 259 | r:and_then(await, jobs.run(submodule_cmd, installer_opts)) 260 | 261 | if plugin.commit then 262 | disp:task_update(plugin_name, fmt('checking out %s...', plugin.commit)) 263 | r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, plugin.commit), installer_opts)) 264 | :map_err(function(err) 265 | return { 266 | msg = fmt('Error checking out commit %s for %s', plugin.commit, plugin_name), 267 | data = { err, output }, 268 | } 269 | end) 270 | end 271 | 272 | r:and_then(await, jobs.run(current_commit_cmd, installer_opts)) 273 | :map_ok(function(_) 274 | plugin.messages = output.data.stdout 275 | end) 276 | :map_err(function(err) 277 | plugin.output = { err = output.data.stderr } 278 | if not err.msg then 279 | return { 280 | msg = fmt('Error installing %s: %s', plugin_name, table.concat(output.data.stderr, '\n')), 281 | data = { err, output }, 282 | } 283 | end 284 | end) 285 | 286 | return r 287 | end) 288 | end 289 | 290 | plugin.remote_url = function() 291 | return async(function() 292 | return await( 293 | jobs.run( 294 | fmt('%s remote get-url origin', config.exec_cmd), 295 | { capture_output = true, cwd = plugin.install_path, options = { env = git.job_env } } 296 | ) 297 | ):map_ok(function(data) 298 | return { remote = data.output.data.stdout[1] } 299 | end) 300 | end) 301 | end 302 | 303 | plugin.updater = function(disp, opts) 304 | return async(function() 305 | local update_info = { err = {}, revs = {}, output = {}, messages = {} } 306 | local function exit_ok(r) 307 | if #update_info.err > 0 or r.exit_code ~= 0 then 308 | return result.err(r) 309 | end 310 | return result.ok(r) 311 | end 312 | 313 | local rev_onread = jobs.logging_callback(update_info.err, update_info.revs) 314 | local rev_callbacks = { stdout = rev_onread, stderr = rev_onread } 315 | disp:task_update(plugin_name, 'checking current commit...') 316 | local r = await( 317 | jobs.run( 318 | rev_cmd, 319 | { success_test = exit_ok, capture_output = rev_callbacks, cwd = install_to, options = { env = git.job_env } } 320 | ) 321 | ):map_err(function(err) 322 | plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} } 323 | 324 | return { 325 | msg = fmt('Error getting current commit for %s: %s', plugin_name, table.concat(update_info.revs, '\n')), 326 | data = err, 327 | } 328 | end) 329 | 330 | local current_branch 331 | disp:task_update(plugin_name, 'checking current branch...') 332 | r:and_then( 333 | await, 334 | jobs.run( 335 | branch_cmd, 336 | { success_test = exit_ok, capture_output = true, cwd = install_to, options = { env = git.job_env } } 337 | ) 338 | ) 339 | :map_ok(function(ok) 340 | current_branch = ok.output.data.stdout[1] 341 | end) 342 | :map_err(function(err) 343 | plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} } 344 | 345 | return { 346 | msg = fmt('Error checking current branch for %s: %s', plugin_name, table.concat(update_info.revs, '\n')), 347 | data = err, 348 | } 349 | end) 350 | 351 | if not needs_checkout then 352 | local origin_branch = '' 353 | disp:task_update(plugin_name, 'checking origin branch...') 354 | local origin_refs_path = util.join_paths(install_to, '.git', 'refs', 'remotes', 'origin', 'HEAD') 355 | local origin_refs_file = vim.loop.fs_open(origin_refs_path, 'r', 438) 356 | if origin_refs_file ~= nil then 357 | local origin_refs_stat = vim.loop.fs_fstat(origin_refs_file) 358 | -- NOTE: This should check for errors 359 | local origin_refs = vim.split(vim.loop.fs_read(origin_refs_file, origin_refs_stat.size, 0), '\n') 360 | vim.loop.fs_close(origin_refs_file) 361 | if #origin_refs > 0 then 362 | origin_branch = string.match(origin_refs[1], [[^ref: refs/remotes/origin/(.*)]]) 363 | end 364 | end 365 | 366 | if current_branch ~= origin_branch then 367 | needs_checkout = true 368 | plugin.branch = origin_branch 369 | end 370 | end 371 | 372 | local update_callbacks = { 373 | stdout = jobs.logging_callback(update_info.err, update_info.output), 374 | stderr = jobs.logging_callback(update_info.err, update_info.output, nil, disp, plugin_name), 375 | } 376 | local update_opts = { 377 | success_test = exit_ok, 378 | capture_output = update_callbacks, 379 | cwd = install_to, 380 | options = { env = git.job_env }, 381 | } 382 | 383 | if needs_checkout then 384 | r:and_then(await, jobs.run(config.exec_cmd .. config.subcommands.fetch, update_opts)) 385 | r:and_then(await, handle_checkouts(plugin, install_to, disp, opts)) 386 | local function merge_output(res) 387 | if res.output ~= nil then 388 | vim.list_extend(update_info.err, res.output.err.stderr) 389 | vim.list_extend(update_info.err, res.output.err.stdout) 390 | vim.list_extend(update_info.output, res.output.data.stdout) 391 | vim.list_extend(update_info.output, res.output.data.stderr) 392 | end 393 | end 394 | 395 | r:map_ok(merge_output) 396 | r:map_err(function(err) 397 | merge_output(err) 398 | plugin.output = { err = vim.list_extend(update_info.err, update_info.output), data = {} } 399 | local errmsg = '' 400 | if err ~= nil and err.msg ~= nil then 401 | errmsg = err.msg 402 | end 403 | return { msg = errmsg .. ' ' .. table.concat(update_info.output, '\n'), data = err.data } 404 | end) 405 | end 406 | 407 | if opts.preview_updates then 408 | disp:task_update(plugin_name, 'fetching updates...') 409 | r:and_then(await, jobs.run(fetch_cmd, update_opts)) 410 | elseif opts.pull_head then 411 | disp:task_update(plugin_name, 'pulling updates from head...') 412 | r:and_then(await, jobs.run(update_head_cmd, update_opts)) 413 | else 414 | disp:task_update(plugin_name, 'pulling updates...') 415 | r:and_then(await, jobs.run(update_cmd, update_opts)):and_then(await, jobs.run(submodule_cmd, update_opts)) 416 | end 417 | r:map_err(function(err) 418 | plugin.output = { err = vim.list_extend(update_info.err, update_info.output), data = {} } 419 | 420 | return { 421 | msg = fmt('Error getting updates for %s: %s', plugin_name, table.concat(update_info.output, '\n')), 422 | data = err, 423 | } 424 | end) 425 | 426 | local post_rev_cmd 427 | if plugin.tag ~= nil then 428 | -- NOTE that any tag wildcard should already been expanded to a specific commit at this point 429 | post_rev_cmd = string.gsub(rev_cmd, 'HEAD', string.format('%s^{}', plugin.tag)) 430 | elseif opts.preview_updates then 431 | post_rev_cmd = string.gsub(rev_cmd, 'HEAD', 'FETCH_HEAD') 432 | else 433 | post_rev_cmd = rev_cmd 434 | end 435 | disp:task_update(plugin_name, 'checking updated commit...') 436 | r:and_then( 437 | await, 438 | jobs.run(post_rev_cmd, { 439 | success_test = exit_ok, 440 | capture_output = rev_callbacks, 441 | cwd = install_to, 442 | options = { env = git.job_env }, 443 | }) 444 | ):map_err(function(err) 445 | plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} } 446 | return { 447 | msg = fmt('Error checking updated commit for %s: %s', plugin_name, table.concat(update_info.revs, '\n')), 448 | data = err, 449 | } 450 | end) 451 | 452 | if r.ok then 453 | if update_info.revs[1] ~= update_info.revs[2] then 454 | local commit_headers_onread = jobs.logging_callback(update_info.err, update_info.messages) 455 | local commit_headers_callbacks = { stdout = commit_headers_onread, stderr = commit_headers_onread } 456 | 457 | local diff_cmd = string.format(config.subcommands.diff, update_info.revs[1], update_info.revs[2]) 458 | local commit_headers_cmd = vim.split(config.exec_cmd .. diff_cmd, '%s+') 459 | for i, arg in ipairs(commit_headers_cmd) do 460 | commit_headers_cmd[i] = string.gsub(arg, 'FMT', config.subcommands.diff_fmt) 461 | end 462 | 463 | disp:task_update(plugin_name, 'getting commit messages...') 464 | r:and_then( 465 | await, 466 | jobs.run(commit_headers_cmd, { 467 | success_test = exit_ok, 468 | capture_output = commit_headers_callbacks, 469 | cwd = install_to, 470 | options = { env = git.job_env }, 471 | }) 472 | ) 473 | 474 | plugin.output = { err = update_info.err, data = update_info.output } 475 | if r.ok then 476 | plugin.messages = update_info.messages 477 | plugin.revs = update_info.revs 478 | end 479 | 480 | if config.mark_breaking_changes then 481 | local commit_bodies = { err = {}, output = {} } 482 | local commit_bodies_onread = jobs.logging_callback(commit_bodies.err, commit_bodies.output) 483 | local commit_bodies_callbacks = { stdout = commit_bodies_onread, stderr = commit_bodies_onread } 484 | local commit_bodies_cmd = config.exec_cmd .. config.subcommands.get_bodies 485 | if opts.preview_updates then 486 | commit_bodies_cmd = config.exec_cmd .. config.subcommands.get_fetch_bodies 487 | end 488 | disp:task_update(plugin_name, 'checking for breaking changes...') 489 | r:and_then( 490 | await, 491 | jobs.run(commit_bodies_cmd, { 492 | success_test = exit_ok, 493 | capture_output = commit_bodies_callbacks, 494 | cwd = install_to, 495 | options = { env = git.job_env }, 496 | }) 497 | ):map_ok(function(ok) 498 | plugin.breaking_commits = {} 499 | mark_breaking_commits(plugin, commit_bodies.output) 500 | return ok 501 | end) 502 | end 503 | else 504 | plugin.revs = update_info.revs 505 | plugin.messages = update_info.messages 506 | end 507 | else 508 | plugin.output.err = vim.list_extend(plugin.output.err, update_info.messages) 509 | end 510 | 511 | r.info = update_info 512 | return r 513 | end) 514 | end 515 | 516 | plugin.diff = function(commit, callback) 517 | async(function() 518 | local diff_cmd = config.exec_cmd .. fmt(config.subcommands.git_diff_fmt, commit) 519 | local diff_info = { err = {}, output = {}, messages = {} } 520 | local diff_onread = jobs.logging_callback(diff_info.err, diff_info.messages) 521 | local diff_callbacks = { stdout = diff_onread, stderr = diff_onread } 522 | return await(jobs.run(diff_cmd, { capture_output = diff_callbacks, cwd = install_to, options = { env = git.job_env } })) 523 | :map_ok(function(_) 524 | return callback(split_messages(diff_info.messages)) 525 | end) 526 | :map_err(function(err) 527 | return callback(nil, err) 528 | end) 529 | end)() 530 | end 531 | 532 | plugin.revert_last = function() 533 | local r = result.ok() 534 | async(function() 535 | local revert_cmd = config.exec_cmd .. config.subcommands.revert 536 | r:and_then( 537 | await, 538 | jobs.run(revert_cmd, { capture_output = true, cwd = install_to, options = { env = git.job_env } }) 539 | ) 540 | if needs_checkout then 541 | r:and_then(await, handle_checkouts(plugin, install_to, nil, {})) 542 | end 543 | return r 544 | end)() 545 | return r 546 | end 547 | 548 | ---Reset the plugin to `commit` 549 | ---@param commit string 550 | plugin.revert_to = function(commit) 551 | assert(type(commit) == 'string', fmt("commit: string expected but '%s' provided", type(commit))) 552 | return async(function() 553 | require('packer.log').debug(fmt("Reverting '%s' to commit '%s'", plugin.name, commit)) 554 | return await(reset(install_to, commit)) 555 | end) 556 | end 557 | 558 | ---Returns HEAD's short hash 559 | ---@return string 560 | plugin.get_rev = function() 561 | return get_rev(plugin) 562 | end 563 | end 564 | 565 | return git 566 | -------------------------------------------------------------------------------- /pack/packer/start/packer.nvim/lua/packer/compile.lua: -------------------------------------------------------------------------------- 1 | -- Compiling plugin specifications to Lua for lazy-loading 2 | local util = require 'packer.util' 3 | local log = require 'packer.log' 4 | local fmt = string.format 5 | local luarocks = require 'packer.luarocks' 6 | 7 | local config 8 | local function cfg(_config) 9 | config = _config.profile 10 | end 11 | 12 | local feature_guard = [[ 13 | if !has('nvim-0.5') 14 | echohl WarningMsg 15 | echom "Invalid Neovim version for packer.nvim!" 16 | echohl None 17 | finish 18 | endif 19 | 20 | packadd packer.nvim 21 | 22 | try 23 | ]] 24 | 25 | local feature_guard_lua = [[ 26 | if vim.api.nvim_call_function('has', {'nvim-0.5'}) ~= 1 then 27 | vim.api.nvim_command('echohl WarningMsg | echom "Invalid Neovim version for packer.nvim! | echohl None"') 28 | return 29 | end 30 | 31 | vim.api.nvim_command('packadd packer.nvim') 32 | 33 | local no_errors, error_msg = pcall(function() 34 | ]] 35 | 36 | local enter_packer_compile = [[ 37 | _G._packer = _G._packer or {} 38 | _G._packer.inside_compile = true 39 | ]] 40 | 41 | local exit_packer_compile = [[ 42 | 43 | _G._packer.inside_compile = false 44 | if _G._packer.needs_bufread == true then 45 | vim.cmd("doautocmd BufRead") 46 | end 47 | _G._packer.needs_bufread = false 48 | ]] 49 | 50 | local catch_errors = [[ 51 | catch 52 | echohl ErrorMsg 53 | echom "Error in packer_compiled: " .. v:exception 54 | echom "Please check your config for correctness" 55 | echohl None 56 | endtry 57 | ]] 58 | 59 | local catch_errors_lua = [[ 60 | end) 61 | 62 | if not no_errors then 63 | error_msg = error_msg:gsub('"', '\\"') 64 | vim.api.nvim_command('echohl ErrorMsg | echom "Error in packer_compiled: '..error_msg..'" | echom "Please check your config for correctness" | echohl None') 65 | end 66 | ]] 67 | 68 | ---@param should_profile boolean 69 | ---@return string 70 | local profile_time = function(should_profile) 71 | return fmt( 72 | [[ 73 | local time 74 | local profile_info 75 | local should_profile = %s 76 | if should_profile then 77 | local hrtime = vim.loop.hrtime 78 | profile_info = {} 79 | time = function(chunk, start) 80 | if start then 81 | profile_info[chunk] = hrtime() 82 | else 83 | profile_info[chunk] = (hrtime() - profile_info[chunk]) / 1e6 84 | end 85 | end 86 | else 87 | time = function(chunk, start) end 88 | end 89 | ]], 90 | vim.inspect(should_profile) 91 | ) 92 | end 93 | 94 | local profile_output = [[ 95 | local function save_profiles(threshold) 96 | local sorted_times = {} 97 | for chunk_name, time_taken in pairs(profile_info) do 98 | sorted_times[#sorted_times + 1] = {chunk_name, time_taken} 99 | end 100 | table.sort(sorted_times, function(a, b) return a[2] > b[2] end) 101 | local results = {} 102 | for i, elem in ipairs(sorted_times) do 103 | if not threshold or threshold and elem[2] > threshold then 104 | results[i] = elem[1] .. ' took ' .. elem[2] .. 'ms' 105 | end 106 | end 107 | if threshold then 108 | table.insert(results, '(Only showing plugins that took longer than ' .. threshold .. ' ms ' .. 'to load)') 109 | end 110 | 111 | _G._packer.profile_output = results 112 | end 113 | ]] 114 | 115 | ---@param threshold number 116 | ---@return string 117 | local conditionally_output_profile = function(threshold) 118 | if threshold then 119 | return fmt( 120 | [[ 121 | if should_profile then save_profiles(%d) end 122 | ]], 123 | threshold 124 | ) 125 | else 126 | return [[ 127 | if should_profile then save_profiles() end 128 | ]] 129 | end 130 | end 131 | 132 | local try_loadstring = [[ 133 | local function try_loadstring(s, component, name) 134 | local success, result = pcall(loadstring(s), name, _G.packer_plugins[name]) 135 | if not success then 136 | vim.schedule(function() 137 | vim.api.nvim_notify('packer.nvim: Error running ' .. component .. ' for ' .. name .. ': ' .. result, vim.log.levels.ERROR, {}) 138 | end) 139 | end 140 | return result 141 | end 142 | ]] 143 | 144 | local module_loader = [[ 145 | local lazy_load_called = {['packer.load'] = true} 146 | local function lazy_load_module(module_name) 147 | local to_load = {} 148 | if lazy_load_called[module_name] then return nil end 149 | lazy_load_called[module_name] = true 150 | for module_pat, plugin_name in pairs(module_lazy_loads) do 151 | if not _G.packer_plugins[plugin_name].loaded and string.match(module_name, module_pat) then 152 | to_load[#to_load + 1] = plugin_name 153 | end 154 | end 155 | 156 | if #to_load > 0 then 157 | require('packer.load')(to_load, {module = module_name}, _G.packer_plugins) 158 | local loaded_mod = package.loaded[module_name] 159 | if loaded_mod then 160 | return function(modname) return loaded_mod end 161 | end 162 | end 163 | end 164 | 165 | if not vim.g.packer_custom_loader_enabled then 166 | table.insert(package.loaders, 1, lazy_load_module) 167 | vim.g.packer_custom_loader_enabled = true 168 | end 169 | ]] 170 | 171 | local function timed_chunk(chunk, name, output_table) 172 | output_table = output_table or {} 173 | output_table[#output_table + 1] = 'time([[' .. name .. ']], true)' 174 | if type(chunk) == 'string' then 175 | output_table[#output_table + 1] = chunk 176 | else 177 | vim.list_extend(output_table, chunk) 178 | end 179 | 180 | output_table[#output_table + 1] = 'time([[' .. name .. ']], false)' 181 | return output_table 182 | end 183 | 184 | local function dump_loaders(loaders) 185 | local result = vim.deepcopy(loaders) 186 | for k, _ in pairs(result) do 187 | if result[k].only_setup or result[k].only_sequence then 188 | result[k].loaded = true 189 | end 190 | result[k].only_setup = nil 191 | result[k].only_sequence = nil 192 | end 193 | 194 | return vim.inspect(result) 195 | end 196 | 197 | local function make_try_loadstring(item, chunk, name) 198 | local bytecode = string.dump(item, true) 199 | local executable_string = 'try_loadstring(' .. vim.inspect(bytecode) .. ', "' .. chunk .. '", "' .. name .. '")' 200 | return executable_string, bytecode 201 | end 202 | 203 | local after_plugin_pattern = table.concat({ 'after', 'plugin', [[**/*.\(vim\|lua\)]] }, util.get_separator()) 204 | local function detect_after_plugin(name, plugin_path) 205 | local path = plugin_path .. util.get_separator() .. after_plugin_pattern 206 | local glob_ok, files = pcall(vim.fn.glob, path, false, true) 207 | if not glob_ok then 208 | if string.find(files, 'E77') then 209 | return { path } 210 | else 211 | log.error('Error compiling ' .. name .. ': ' .. vim.inspect(files)) 212 | error(files) 213 | end 214 | elseif #files > 0 then 215 | return files 216 | end 217 | 218 | return nil 219 | end 220 | 221 | local ftdetect_patterns = { 222 | table.concat({ 'ftdetect', [[**/*.\(vim\|lua\)]] }, util.get_separator()), 223 | table.concat({ 'after', 'ftdetect', [[**/*.\(vim\|lua\)]] }, util.get_separator()), 224 | } 225 | local function detect_ftdetect(name, plugin_path) 226 | local paths = { 227 | plugin_path .. util.get_separator() .. ftdetect_patterns[1], 228 | plugin_path .. util.get_separator() .. ftdetect_patterns[2], 229 | } 230 | local source_paths = {} 231 | for i = 1, 2 do 232 | local path = paths[i] 233 | local glob_ok, files = pcall(vim.fn.glob, path, false, true) 234 | if not glob_ok then 235 | if string.find(files, 'E77') then 236 | source_paths[#source_paths + 1] = path 237 | else 238 | log.error('Error compiling ' .. name .. ': ' .. vim.inspect(files)) 239 | error(files) 240 | end 241 | elseif #files > 0 then 242 | vim.list_extend(source_paths, files) 243 | end 244 | end 245 | 246 | return source_paths 247 | end 248 | 249 | local source_dirs = { 'ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin' } 250 | local function detect_bufread(plugin_path) 251 | local path = plugin_path 252 | for i = 1, 4 do 253 | if #vim.fn.finddir(source_dirs[i], path) > 0 then 254 | return true 255 | end 256 | end 257 | return false 258 | end 259 | 260 | local function make_loaders(_, plugins, output_lua, should_profile) 261 | local loaders = {} 262 | local configs = {} 263 | local rtps = {} 264 | local setup = {} 265 | local fts = {} 266 | local events = {} 267 | local condition_ids = {} 268 | local commands = {} 269 | local keymaps = {} 270 | local after = {} 271 | local fns = {} 272 | local ftdetect_paths = {} 273 | local module_lazy_loads = {} 274 | for name, plugin in pairs(plugins) do 275 | if not plugin.disable then 276 | plugin.simple_load = true 277 | local quote_name = "'" .. name .. "'" 278 | if plugin.config and not plugin.executable_config then 279 | plugin.simple_load = false 280 | plugin.executable_config = {} 281 | if type(plugin.config) ~= 'table' then 282 | plugin.config = { plugin.config } 283 | end 284 | for i, config_item in ipairs(plugin.config) do 285 | local executable_string = config_item 286 | if type(config_item) == 'function' then 287 | local bytecode 288 | executable_string, bytecode = make_try_loadstring(config_item, 'config', name) 289 | plugin.config[i] = bytecode 290 | end 291 | 292 | table.insert(plugin.executable_config, executable_string) 293 | end 294 | end 295 | 296 | local path = plugin.install_path 297 | if plugin.rtp then 298 | path = util.join_paths(plugin.install_path, plugin.rtp) 299 | table.insert(rtps, path) 300 | end 301 | 302 | loaders[name] = { 303 | loaded = not plugin.opt, 304 | config = plugin.config, 305 | path = path, 306 | only_sequence = plugin.manual_opt == nil, 307 | only_setup = false, 308 | } 309 | 310 | if plugin.opt then 311 | plugin.simple_load = false 312 | loaders[name].after_files = detect_after_plugin(name, loaders[name].path) 313 | if plugin.bufread ~= nil then 314 | loaders[name].needs_bufread = plugin.bufread 315 | else 316 | loaders[name].needs_bufread = detect_bufread(loaders[name].path) 317 | end 318 | end 319 | 320 | if plugin.setup then 321 | plugin.simple_load = false 322 | if type(plugin.setup) ~= 'table' then 323 | plugin.setup = { plugin.setup } 324 | end 325 | for i, setup_item in ipairs(plugin.setup) do 326 | if type(setup_item) == 'function' then 327 | plugin.setup[i], _ = make_try_loadstring(setup_item, 'setup', name) 328 | end 329 | end 330 | 331 | loaders[name].only_setup = plugin.manual_opt == nil 332 | setup[name] = plugin.setup 333 | end 334 | 335 | -- Keep this as first opt loader to maintain only_cond ? 336 | if plugin.cond ~= nil then 337 | plugin.simple_load = false 338 | loaders[name].only_sequence = false 339 | loaders[name].only_setup = false 340 | loaders[name].only_cond = true 341 | if type(plugin.cond) ~= 'table' then 342 | plugin.cond = { plugin.cond } 343 | end 344 | 345 | for _, condition in ipairs(plugin.cond) do 346 | loaders[name].cond = {} 347 | if type(condition) == 'function' then 348 | _, condition = make_try_loadstring(condition, 'condition', name) 349 | elseif type(condition) == 'string' then 350 | condition = 'return ' .. condition 351 | end 352 | 353 | condition_ids[condition] = condition_ids[condition] or {} 354 | table.insert(loaders[name].cond, condition) 355 | table.insert(condition_ids[condition], name) 356 | end 357 | end 358 | 359 | -- Add the git URL for displaying in PackerStatus and PackerSync. https://github.com/wbthomason/packer.nvim/issues/542 360 | loaders[name].url = plugin.url 361 | 362 | if plugin.ft then 363 | plugin.simple_load = false 364 | loaders[name].only_sequence = false 365 | loaders[name].only_setup = false 366 | loaders[name].only_cond = false 367 | vim.list_extend(ftdetect_paths, detect_ftdetect(name, loaders[name].path)) 368 | if type(plugin.ft) == 'string' then 369 | plugin.ft = { plugin.ft } 370 | end 371 | for _, ft in ipairs(plugin.ft) do 372 | fts[ft] = fts[ft] or {} 373 | table.insert(fts[ft], quote_name) 374 | end 375 | end 376 | 377 | if plugin.event then 378 | plugin.simple_load = false 379 | loaders[name].only_sequence = false 380 | loaders[name].only_setup = false 381 | loaders[name].only_cond = false 382 | if type(plugin.event) == 'string' then 383 | if not plugin.event:find '%s' then 384 | plugin.event = { plugin.event .. ' *' } 385 | else 386 | plugin.event = { plugin.event } 387 | end 388 | end 389 | 390 | for _, event in ipairs(plugin.event) do 391 | if event:sub(#event, -1) ~= '*' and not event:find '%s' then 392 | event = event .. ' *' 393 | end 394 | events[event] = events[event] or {} 395 | table.insert(events[event], quote_name) 396 | end 397 | end 398 | 399 | if plugin.cmd then 400 | plugin.simple_load = false 401 | loaders[name].only_sequence = false 402 | loaders[name].only_setup = false 403 | loaders[name].only_cond = false 404 | if type(plugin.cmd) == 'string' then 405 | plugin.cmd = { plugin.cmd } 406 | end 407 | 408 | loaders[name].commands = {} 409 | for _, command in ipairs(plugin.cmd) do 410 | commands[command] = commands[command] or {} 411 | table.insert(loaders[name].commands, command) 412 | table.insert(commands[command], quote_name) 413 | end 414 | end 415 | 416 | if plugin.keys then 417 | plugin.simple_load = false 418 | loaders[name].only_sequence = false 419 | loaders[name].only_setup = false 420 | loaders[name].only_cond = false 421 | if type(plugin.keys) == 'string' then 422 | plugin.keys = { plugin.keys } 423 | end 424 | loaders[name].keys = {} 425 | for _, keymap in ipairs(plugin.keys) do 426 | if type(keymap) == 'string' then 427 | keymap = { '', keymap } 428 | end 429 | keymaps[keymap] = keymaps[keymap] or {} 430 | table.insert(loaders[name].keys, keymap) 431 | table.insert(keymaps[keymap], quote_name) 432 | end 433 | end 434 | 435 | if plugin.after then 436 | plugin.simple_load = false 437 | loaders[name].only_setup = false 438 | 439 | if type(plugin.after) == 'string' then 440 | plugin.after = { plugin.after } 441 | end 442 | 443 | for _, other_plugin in ipairs(plugin.after) do 444 | after[other_plugin] = after[other_plugin] or {} 445 | table.insert(after[other_plugin], name) 446 | end 447 | end 448 | 449 | if plugin.wants then 450 | plugin.simple_load = false 451 | if type(plugin.wants) == 'string' then 452 | plugin.wants = { plugin.wants } 453 | end 454 | loaders[name].wants = plugin.wants 455 | end 456 | 457 | if plugin.fn then 458 | plugin.simple_load = false 459 | loaders[name].only_sequence = false 460 | loaders[name].only_setup = false 461 | if type(plugin.fn) == 'string' then 462 | plugin.fn = { plugin.fn } 463 | end 464 | for _, fn in ipairs(plugin.fn) do 465 | fns[fn] = fns[fn] or {} 466 | table.insert(fns[fn], quote_name) 467 | end 468 | end 469 | 470 | if plugin.module or plugin.module_pattern then 471 | plugin.simple_load = false 472 | loaders[name].only_sequence = false 473 | loaders[name].only_setup = false 474 | loaders[name].only_cond = false 475 | 476 | if plugin.module then 477 | if type(plugin.module) == 'string' then 478 | plugin.module = { plugin.module } 479 | end 480 | 481 | for _, module_name in ipairs(plugin.module) do 482 | module_lazy_loads['^' .. vim.pesc(module_name)] = name 483 | end 484 | else 485 | if type(plugin.module_pattern) == 'string' then 486 | plugin.module_pattern = { plugin.module_pattern } 487 | end 488 | 489 | for _, module_pattern in ipairs(plugin.module_pattern) do 490 | module_lazy_loads[module_pattern] = name 491 | end 492 | end 493 | end 494 | 495 | if plugin.config and (not plugin.opt or loaders[name].only_setup) then 496 | plugin.simple_load = false 497 | plugin.only_config = true 498 | configs[name] = plugin.executable_config 499 | end 500 | end 501 | end 502 | 503 | local ft_aucmds = {} 504 | for ft, names in pairs(fts) do 505 | table.insert( 506 | ft_aucmds, 507 | fmt( 508 | 'vim.cmd [[au FileType %s ++once lua require("packer.load")({%s}, { ft = "%s" }, _G.packer_plugins)]]', 509 | ft, 510 | table.concat(names, ', '), 511 | ft 512 | ) 513 | ) 514 | end 515 | 516 | local event_aucmds = {} 517 | for event, names in pairs(events) do 518 | table.insert( 519 | event_aucmds, 520 | fmt( 521 | 'vim.cmd [[au %s ++once lua require("packer.load")({%s}, { event = "%s" }, _G.packer_plugins)]]', 522 | event, 523 | table.concat(names, ', '), 524 | event:gsub([[\]], [[\\]]) 525 | ) 526 | ) 527 | end 528 | 529 | local config_lines = {} 530 | for name, plugin_config in pairs(configs) do 531 | local lines = { '-- Config for: ' .. name } 532 | timed_chunk(plugin_config, 'Config for ' .. name, lines) 533 | vim.list_extend(config_lines, lines) 534 | end 535 | 536 | local rtp_line = '' 537 | for _, rtp in ipairs(rtps) do 538 | rtp_line = rtp_line .. ' .. ",' .. vim.fn.escape(rtp, '\\,') .. '"' 539 | end 540 | 541 | if rtp_line ~= '' then 542 | rtp_line = 'vim.o.runtimepath = vim.o.runtimepath' .. rtp_line 543 | end 544 | 545 | local setup_lines = {} 546 | for name, plugin_setup in pairs(setup) do 547 | local lines = { '-- Setup for: ' .. name } 548 | timed_chunk(plugin_setup, 'Setup for ' .. name, lines) 549 | if loaders[name].only_setup then 550 | timed_chunk('vim.cmd [[packadd ' .. name .. ']]', 'packadd for ' .. name, lines) 551 | end 552 | 553 | vim.list_extend(setup_lines, lines) 554 | end 555 | 556 | local conditionals = {} 557 | for _, names in pairs(condition_ids) do 558 | for _, name in ipairs(names) do 559 | if loaders[name].only_cond then 560 | timed_chunk( 561 | fmt(' require("packer.load")({"%s"}, {}, _G.packer_plugins)', name), 562 | 'Conditional loading of ' .. name, 563 | conditionals 564 | ) 565 | end 566 | end 567 | end 568 | 569 | local command_defs = {} 570 | for command, names in pairs(commands) do 571 | local command_line 572 | if string.match(command, '^%w+$') then 573 | -- Better command completions here are due to @folke and @lewis6991 574 | command_line = fmt( 575 | [[pcall(vim.api.nvim_create_user_command, '%s', function(cmdargs) 576 | require('packer.load')({%s}, { cmd = '%s', l1 = cmdargs.line1, l2 = cmdargs.line2, bang = cmdargs.bang, args = cmdargs.args, mods = cmdargs.mods }, _G.packer_plugins) 577 | end, 578 | {nargs = '*', range = true, bang = true, complete = function() 579 | require('packer.load')({%s}, {}, _G.packer_plugins) 580 | return vim.fn.getcompletion('%s ', 'cmdline') 581 | end})]], 582 | command, 583 | table.concat(names, ', '), 584 | command, 585 | table.concat(names, ', '), 586 | command, 587 | command 588 | ) 589 | else 590 | command_line = fmt( 591 | 'pcall(vim.cmd, [[au CmdUndefined %s ++once lua require"packer.load"({%s}, {}, _G.packer_plugins)]])', 592 | command, 593 | table.concat(names, ', ') 594 | ) 595 | end 596 | command_defs[#command_defs + 1] = command_line 597 | end 598 | 599 | local keymap_defs = {} 600 | for keymap, names in pairs(keymaps) do 601 | local prefix = nil 602 | if keymap[1] ~= 'i' then 603 | prefix = '' 604 | end 605 | local escaped_map_lt = string.gsub(keymap[2], '<', '') 606 | local escaped_map = string.gsub(escaped_map_lt, '([\\"])', '\\%1') 607 | local keymap_line = fmt( 608 | 'vim.cmd [[%snoremap %s lua require("packer.load")({%s}, { keys = "%s"%s }, _G.packer_plugins)]]', 609 | keymap[1], 610 | keymap[2], 611 | table.concat(names, ', '), 612 | escaped_map, 613 | prefix == nil and '' or (', prefix = "' .. prefix .. '"') 614 | ) 615 | 616 | table.insert(keymap_defs, keymap_line) 617 | end 618 | 619 | local sequence_loads = {} 620 | for pre, posts in pairs(after) do 621 | if plugins[pre] == nil then 622 | error(string.format('Dependency %s for %s not found', pre, vim.inspect(posts))) 623 | end 624 | 625 | if plugins[pre].opt then 626 | loaders[pre].after = posts 627 | elseif plugins[pre].only_config then 628 | loaders[pre].after = posts 629 | loaders[pre].only_sequence = true 630 | loaders[pre].only_config = true 631 | end 632 | 633 | if plugins[pre].simple_load or plugins[pre].opt or plugins[pre].only_config then 634 | for _, name in ipairs(posts) do 635 | loaders[name].load_after = {} 636 | sequence_loads[name] = sequence_loads[name] or {} 637 | table.insert(sequence_loads[name], pre) 638 | end 639 | end 640 | end 641 | 642 | local fn_aucmds = {} 643 | for fn, names in pairs(fns) do 644 | table.insert( 645 | fn_aucmds, 646 | fmt( 647 | 'vim.cmd[[au FuncUndefined %s ++once lua require("packer.load")({%s}, {}, _G.packer_plugins)]]', 648 | fn, 649 | table.concat(names, ', ') 650 | ) 651 | ) 652 | end 653 | 654 | local sequence_lines = {} 655 | local graph = {} 656 | for name, precedents in pairs(sequence_loads) do 657 | graph[name] = graph[name] or { in_links = {}, out_links = {} } 658 | for _, pre in ipairs(precedents) do 659 | graph[pre] = graph[pre] or { in_links = {}, out_links = {} } 660 | graph[name].in_links[pre] = true 661 | table.insert(graph[pre].out_links, name) 662 | end 663 | end 664 | 665 | local frontier = {} 666 | for name, links in pairs(graph) do 667 | if next(links.in_links) == nil then 668 | table.insert(frontier, name) 669 | end 670 | end 671 | 672 | while next(frontier) ~= nil do 673 | local plugin = table.remove(frontier) 674 | if loaders[plugin].only_sequence and not (loaders[plugin].only_setup or loaders[plugin].only_config) then 675 | table.insert(sequence_lines, 'vim.cmd [[ packadd ' .. plugin .. ' ]]') 676 | if plugins[plugin].config then 677 | local lines = { '', '-- Config for: ' .. plugin } 678 | vim.list_extend(lines, plugins[plugin].executable_config) 679 | table.insert(lines, '') 680 | vim.list_extend(sequence_lines, lines) 681 | end 682 | end 683 | 684 | for _, name in ipairs(graph[plugin].out_links) do 685 | if not loaders[plugin].only_sequence then 686 | loaders[name].only_sequence = false 687 | loaders[name].load_after[plugin] = true 688 | end 689 | 690 | graph[name].in_links[plugin] = nil 691 | if next(graph[name].in_links) == nil then 692 | table.insert(frontier, name) 693 | end 694 | end 695 | 696 | graph[plugin] = nil 697 | end 698 | 699 | if next(graph) then 700 | log.warn 'Cycle detected in sequenced loads! Load order may be incorrect' 701 | -- TODO: This should actually just output the cycle, then continue with toposort. But I'm too 702 | -- lazy to do that right now, so. 703 | for plugin, _ in pairs(graph) do 704 | table.insert(sequence_lines, 'vim.cmd [[ packadd ' .. plugin .. ' ]]') 705 | if plugins[plugin].config then 706 | local lines = { '-- Config for: ' .. plugin } 707 | vim.list_extend(lines, plugins[plugin].config) 708 | vim.list_extend(sequence_lines, lines) 709 | end 710 | end 711 | end 712 | 713 | -- Output everything: 714 | 715 | -- First, the Lua code 716 | local result = { (output_lua and '--' or '"') .. ' Automatically generated packer.nvim plugin loader code\n' } 717 | if output_lua then 718 | table.insert(result, feature_guard_lua) 719 | else 720 | table.insert(result, feature_guard) 721 | table.insert(result, 'lua << END') 722 | end 723 | table.insert(result, enter_packer_compile) 724 | table.insert(result, profile_time(should_profile)) 725 | table.insert(result, profile_output) 726 | timed_chunk(luarocks.generate_path_setup(), 'Luarocks path setup', result) 727 | timed_chunk(try_loadstring, 'try_loadstring definition', result) 728 | timed_chunk(fmt('_G.packer_plugins = %s\n', dump_loaders(loaders)), 'Defining packer_plugins', result) 729 | -- Then the runtimepath line 730 | if rtp_line ~= '' then 731 | table.insert(result, '-- Runtimepath customization') 732 | timed_chunk(rtp_line, 'Runtimepath customization', result) 733 | end 734 | 735 | -- Then the module lazy loads 736 | if next(module_lazy_loads) then 737 | table.insert(result, 'local module_lazy_loads = ' .. vim.inspect(module_lazy_loads)) 738 | table.insert(result, module_loader) 739 | end 740 | 741 | -- Then setups, configs, and conditionals 742 | if next(setup_lines) then 743 | vim.list_extend(result, setup_lines) 744 | end 745 | if next(config_lines) then 746 | vim.list_extend(result, config_lines) 747 | end 748 | if next(conditionals) then 749 | table.insert(result, '-- Conditional loads') 750 | vim.list_extend(result, conditionals) 751 | end 752 | 753 | -- The sequenced loads 754 | if next(sequence_lines) then 755 | table.insert(result, '-- Load plugins in order defined by `after`') 756 | timed_chunk(sequence_lines, 'Sequenced loading', result) 757 | end 758 | 759 | -- The command and keymap definitions 760 | if next(command_defs) then 761 | table.insert(result, '\n-- Command lazy-loads') 762 | timed_chunk(command_defs, 'Defining lazy-load commands', result) 763 | table.insert(result, '') 764 | end 765 | 766 | if next(keymap_defs) then 767 | table.insert(result, '-- Keymap lazy-loads') 768 | timed_chunk(keymap_defs, 'Defining lazy-load keymaps', result) 769 | table.insert(result, '') 770 | end 771 | 772 | -- The filetype, event and function autocommands 773 | local some_ft = next(ft_aucmds) ~= nil 774 | local some_event = next(event_aucmds) ~= nil 775 | local some_fn = next(fn_aucmds) ~= nil 776 | if some_ft or some_event or some_fn then 777 | table.insert(result, 'vim.cmd [[augroup packer_load_aucmds]]\nvim.cmd [[au!]]') 778 | end 779 | 780 | if some_ft then 781 | table.insert(result, ' -- Filetype lazy-loads') 782 | timed_chunk(ft_aucmds, 'Defining lazy-load filetype autocommands', result) 783 | end 784 | 785 | if some_event then 786 | table.insert(result, ' -- Event lazy-loads') 787 | timed_chunk(event_aucmds, 'Defining lazy-load event autocommands', result) 788 | end 789 | 790 | if some_fn then 791 | table.insert(result, ' -- Function lazy-loads') 792 | timed_chunk(fn_aucmds, 'Defining lazy-load function autocommands', result) 793 | end 794 | 795 | if some_ft or some_event or some_fn then 796 | table.insert(result, 'vim.cmd("augroup END")') 797 | end 798 | if next(ftdetect_paths) then 799 | table.insert(result, 'vim.cmd [[augroup filetypedetect]]') 800 | for _, path in ipairs(ftdetect_paths) do 801 | local escaped_path = vim.fn.escape(path, ' ') 802 | timed_chunk('vim.cmd [[source ' .. escaped_path .. ']]', 'Sourcing ftdetect script at: ' .. escaped_path, result) 803 | end 804 | 805 | table.insert(result, 'vim.cmd("augroup END")') 806 | end 807 | 808 | table.insert(result, exit_packer_compile) 809 | 810 | table.insert(result, conditionally_output_profile(config.threshold)) 811 | if output_lua then 812 | table.insert(result, catch_errors_lua) 813 | else 814 | table.insert(result, 'END\n') 815 | table.insert(result, catch_errors) 816 | end 817 | return table.concat(result, '\n') 818 | end 819 | 820 | local compile = setmetatable({ cfg = cfg }, { __call = make_loaders }) 821 | 822 | compile.opt_keys = { 'after', 'cmd', 'ft', 'keys', 'event', 'cond', 'setup', 'fn', 'module', 'module_pattern' } 823 | 824 | return compile 825 | --------------------------------------------------------------------------------