[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: wbthomason\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report--packer-v1-.md",
    "content": "---\nname: Bug report (packer v1)\nabout: Report a bug in packer.nvim, v1 (current master branch)\ntitle: ''\nlabels: bug, v1\nassignees: ''\n\n---\n\n<!-- Before creating an issue, please search the issue tracker and make sure packer.nvim is up to date -->\n<!-- If your issue is a general usage question, please create a GitHub discussions thread: https://github.com/wbthomason/packer.nvim/discussions -->\n\n- `nvim --version`:\n- `git --version`:\n- Operating system/version:\n- Terminal name/version:\n\n### Steps to reproduce\n\n### Actual behaviour\n\n### Expected behaviour\n\n### packer files\n\n<details>\n<summary>Plugin specification file(s)</summary>\n\nPost or link your plugin specification files here, if you aren't able to provide a minimal\nreproducer\n\n</details>\n\n<details>\n<summary>packer log file</summary>\n\nPost the contents of ~/.cache/nvim/packer.nvim.log here\n\n</details>\n\n<details>\n<summary>packer compiled file</summary>\n\nPost the contents of `packer_compiled.vim` here\n\n</details>\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report--packer-v2-.md",
    "content": "---\nname: Bug report (packer v2)\nabout: Report a bug in packer.nvim, v2 (currently in alpha)\ntitle: ''\nlabels: bug, fix in v2\nassignees: ''\n\n---\n\n<!-- Before creating an issue, please search the issue tracker and make sure packer.nvim is up to date -->\n<!-- If your issue is a general usage question, please create a GitHub discussions thread: https://github.com/wbthomason/packer.nvim/discussions -->\n<!-- Please do not report missing features that you would like added back using this template! -->\n\n- `nvim --version`:\n- `git --version`:\n- Operating system/version:\n- `packer` commit:\n\n### Observed behaviour\n\n### Expected behaviour\n\n### Steps to reproduce\n\n### packer files\n\n<details>\n<summary>Plugin specification table</summary>\n\nPost or link to a file containing your table of plugin specifications here, if you aren't able to provide a minimal reproducer\n\n</details>\n\n<details>\n<summary>packer log file</summary>\n\nPost the contents of ~/.cache/nvim/packer.nvim.log here\n\n</details>\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest a feature for packer.nvim\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n<!-- Before creating an issue, please search the issue tracker and make sure packer.nvim is up to date -->\n<!-- If your issue is a general usage question, please create a GitHub discussions thread: https://github.com/wbthomason/packer.nvim/discussions -->\n\n### Describe the feature\n"
  },
  {
    "path": ".github/workflows/formatting.yaml",
    "content": "name: formatting\non:\n  push:\n    paths-ignore:\n      - \".github/**\"\n      - \"*.md\"\n    branches: [\"master\"]\n\njobs:\n  stylua:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: JohnnyMorganz/stylua-action@1.0.0\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          args: --config-path=stylua.toml lua/\n      - name: Commit files\n        run: |\n          git config --local user.email \"41898282+github-actions[bot]@users.noreply.github.com\"\n          git config --local user.name \"github-actions[bot]\"\n          if ! [[ -z $(git status -s) ]]; then\n            git commit -m \"chore: format with stylua\" lua/*\n          fi\n      - name: Push changes\n        uses: ad-m/github-push-action@master\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          branch: ${{ github.ref }}\n"
  },
  {
    "path": ".github/workflows/test.yaml",
    "content": "---\nname: CI\non:\n  pull_request: ~\n  push:\n    branches:\n      - master\n\njobs:\n  build:\n    name: Run tests\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: true\n      matrix:\n        neovim_branch: [\"v0.5.0\", \"v0.6.1\", \"nightly\"]\n\n    steps:\n      # Checkout packer\n      - uses: actions/checkout@v2\n\n      # Prepare taken from telescope\n      - name: Prepare\n        run: |\n          mkdir -p _neovim\n          curl -sL https://github.com/neovim/neovim/releases/download/${{ matrix.neovim_branch }}/nvim-linux64.tar.gz | tar xzf - --strip-components=1 -C \"${PWD}/_neovim\"\n          mkdir -p ~/.local/share/nvim/site/pack/vendor/start\n          git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim\n          ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start\n\n      - name: Run tests\n        run: |\n          export PATH=\"${PWD}/_neovim/bin:${PATH}\"\n          export VIM=\"${PWD}/_neovim/share/nvim/runtime\"\n          nvim --version\n          make test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Compiled Lua sources\nluac.out\n\n# luarocks build files\n*.src.rock\n*.zip\n*.tar.gz\n\n# Object files\n*.o\n*.os\n*.ko\n*.obj\n*.elf\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n*.def\n*.exp\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Vim swap files\n*.swp\n\ndoc/tags\n"
  },
  {
    "path": ".lua-format",
    "content": "align_args: true\nalign_parameter: true\nalign_table_field: true\nbreak_after_functioncall_lp: false\nbreak_after_functiondef_lp: false\nbreak_after_operator: false \nbreak_after_table_lb: true\nbreak_before_functioncall_rp: true\nbreak_before_functiondef_rp: true\nbreak_before_table_rb: true\nchop_down_kv_table: true\nchop_down_parameter: true\nchop_down_table: false\ncolumn_limit: 100\ncolumn_table_limit: 100\ncontinuation_indent_width: 2\ndouble_quote_to_single_quote: false\nextra_sep_at_table_end: false\nindent_width: 2\nkeep_simple_control_block_one_line: true\nkeep_simple_function_one_line: true\nsingle_quote_to_double_quote: false\nspaces_before_call: 1\ntab_width: 2\ntable_sep: ','\nuse_tab: false\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM archlinux:base-devel\nWORKDIR /setup\nRUN pacman -Sy git neovim python --noconfirm\nRUN useradd -m test\n\nUSER test\nRUN git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim\nRUN mkdir -p /home/test/.cache/nvim/packer.nvim\nRUN touch /home/test/.cache/nvim/packer.nvim/test_completion{,1,2,3}\n\nUSER test\nRUN mkdir -p /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim/\nWORKDIR /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim/\nCOPY . ./\n\nUSER root\nRUN chmod 777 -R /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim\nRUN touch /home/test/.cache/nvim/packer.nvim/not_writeable\n\nUSER test\nENTRYPOINT make test\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Wil Thomason\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "test:\n\tnvim --headless --noplugin -u tests/minimal.vim -c \"PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal.vim' }\"\nrun:\n\tdocker build . -t neovim-stable:latest && docker run --rm -it --entrypoint bash neovim-stable:latest\nrun-test:\n\tdocker build . -t neovim-stable:latest && docker run --rm neovim-stable:latest\n"
  },
  {
    "path": "README.md",
    "content": "**NOTICE:**\n\nThis repository is currently unmaintained. For the time being (as of August, 2023), it is recommended to use one of the following plugin managers instead:\n\n- [lazy.nvim](https://github.com/folke/lazy.nvim): Most stable and maintained plugin manager for Nvim.\n- [pckr.nvim](https://github.com/lewis6991/pckr.nvim): Spiritual successor of packer.nvim. Functional but not as stable as lazy.nvim.\n\n# packer.nvim\n\n[![Gitter](https://badges.gitter.im/packer-nvim/community.svg)](https://gitter.im/packer-nvim/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)\n\n[`use-package`](https://github.com/jwiegley/use-package) inspired plugin/package management for\nNeovim.\n\nHave questions? Start a [discussion](https://github.com/wbthomason/packer.nvim/discussions).\n\nHave a problem or idea? Make an [issue](https://github.com/wbthomason/packer.nvim/issues) or a [PR](https://github.com/wbthomason/packer.nvim/pulls).\n\n**Packer is built on native packages. You may wish to read `:h packages` before continuing**\n\n## Table of Contents\n1. [Features](#features)\n2. [Requirements](#requirements)\n3. [Quickstart](#quickstart)\n4. [Bootstrapping](#bootstrapping)\n5. [Usage](#usage)\n    1. [The startup function](#the-startup-function)\n    2. [Custom Initialization](#custom-initialization)\n    3. [Specifying Plugins](#specifying-plugins)\n    4. [Performing plugin management operations](#performing-plugin-management-operations)\n    5. [Extending packer](#extending-packer)\n    6. [Compiling Lazy-Loaders](#compiling-lazy-loaders)\n\t7. [User autocommands](#user-autocommands)\n\t8. [Using a floating window](#using-a-floating-window)\n6. [Profiling](#profiling)\n7. [Debugging](#debugging)\n8. [Compatibility and known issues](#compatibility-and-known-issues)\n9. [Contributors](#contributors)\n\n## Features\n- Declarative plugin specification\n- Support for dependencies\n- Support for Luarocks dependencies\n- Expressive configuration and lazy-loading options\n- Automatically compiles efficient lazy-loading code to improve startup time\n- Uses native packages\n- Extensible\n- Written in Lua, configured in Lua\n- Post-install/update hooks\n- Uses jobs for async installation\n- Support for `git` tags, branches, revisions, submodules\n- Support for local plugins\n\n## Requirements\n- You need to be running **Neovim v0.5.0+**\n- If you are on Windows 10, you need developer mode enabled in order to use local plugins (creating\n  symbolic links requires admin privileges on Windows - credit to @TimUntersberger for this note)\n\n## Quickstart\nTo get started, first clone this repository to somewhere on your `packpath`, e.g.:\n\n> Unix, Linux Installation\n\n```shell\ngit clone --depth 1 https://github.com/wbthomason/packer.nvim\\\n ~/.local/share/nvim/site/pack/packer/start/packer.nvim\n```\n\nIf you use Arch Linux, there is also [an AUR\npackage](https://aur.archlinux.org/packages/nvim-packer-git/).\n\n> Windows Powershell Installation\n\n```shell\ngit clone https://github.com/wbthomason/packer.nvim \"$env:LOCALAPPDATA\\nvim-data\\site\\pack\\packer\\start\\packer.nvim\"\n```\n\nThen you can write your plugin specification in Lua, e.g. (in `~/.config/nvim/lua/plugins.lua`):\n\n```lua\n-- This file can be loaded by calling `lua require('plugins')` from your init.vim\n\n-- Only required if you have packer configured as `opt`\nvim.cmd [[packadd packer.nvim]]\n\nreturn require('packer').startup(function(use)\n  -- Packer can manage itself\n  use 'wbthomason/packer.nvim'\n\n  -- Simple plugins can be specified as strings\n  use 'rstacruz/vim-closer'\n\n  -- Lazy loading:\n  -- Load on specific commands\n  use {'tpope/vim-dispatch', opt = true, cmd = {'Dispatch', 'Make', 'Focus', 'Start'}}\n\n  -- Load on an autocommand event\n  use {'andymass/vim-matchup', event = 'VimEnter'}\n\n  -- Load on a combination of conditions: specific filetypes or commands\n  -- Also run code after load (see the \"config\" key)\n  use {\n    'w0rp/ale',\n    ft = {'sh', 'zsh', 'bash', 'c', 'cpp', 'cmake', 'html', 'markdown', 'racket', 'vim', 'tex'},\n    cmd = 'ALEEnable',\n    config = 'vim.cmd[[ALEEnable]]'\n  }\n\n  -- Plugins can have dependencies on other plugins\n  use {\n    'haorenW1025/completion-nvim',\n    opt = true,\n    requires = {{'hrsh7th/vim-vsnip', opt = true}, {'hrsh7th/vim-vsnip-integ', opt = true}}\n  }\n\n  -- Plugins can also depend on rocks from luarocks.org:\n  use {\n    'my/supercoolplugin',\n    rocks = {'lpeg', {'lua-cjson', version = '2.1.0'}}\n  }\n\n  -- You can specify rocks in isolation\n  use_rocks 'penlight'\n  use_rocks {'lua-resty-http', 'lpeg'}\n\n  -- Local plugins can be included\n  use '~/projects/personal/hover.nvim'\n\n  -- Plugins can have post-install/update hooks\n  use {'iamcco/markdown-preview.nvim', run = 'cd app && yarn install', cmd = 'MarkdownPreview'}\n\n  -- Post-install/update hook with neovim command\n  use { 'nvim-treesitter/nvim-treesitter', run = ':TSUpdate' }\n\n  -- Post-install/update hook with call of vimscript function with argument\n  use { 'glacambre/firenvim', run = function() vim.fn['firenvim#install'](0) end }\n\n  -- Use specific branch, dependency and run lua file after load\n  use {\n    'glepnir/galaxyline.nvim', branch = 'main', config = function() require'statusline' end,\n    requires = {'kyazdani42/nvim-web-devicons'}\n  }\n\n  -- Use dependency and run lua function after load\n  use {\n    'lewis6991/gitsigns.nvim', requires = { 'nvim-lua/plenary.nvim' },\n    config = function() require('gitsigns').setup() end\n  }\n\n  -- You can specify multiple plugins in a single call\n  use {'tjdevries/colorbuddy.vim', {'nvim-treesitter/nvim-treesitter', opt = true}}\n\n  -- You can alias plugin names\n  use {'dracula/vim', as = 'dracula'}\nend)\n```\n\nNote that if you get linter complaints about `use` being an undefined global, these errors are\nspurious - `packer` injects `use` into the scope of the function passed to `startup`.\nIf these errors bother you, the easiest fix is to simply specify `use` as an argument to the\nfunction you pass to `startup`, e.g.\n```lua\npacker.startup(function(use)\n...your config...\nend)\n```\n\n`packer` provides the following commands after you've run and configured `packer` with `require('packer').startup(...)`:\n\n```\n-- You must run this or `PackerSync` whenever you make changes to your plugin configuration\n-- Regenerate compiled loader file\n:PackerCompile\n\n-- Remove any disabled or unused plugins\n:PackerClean\n\n-- Clean, then install missing plugins\n:PackerInstall\n\n-- Clean, then update and install plugins\n-- supports the `--preview` flag as an optional first argument to preview updates\n:PackerUpdate\n\n-- Perform `PackerUpdate` and then `PackerCompile`\n-- supports the `--preview` flag as an optional first argument to preview updates\n:PackerSync\n\n-- Show list of installed plugins\n:PackerStatus\n\n-- Loads opt plugin immediately\n:PackerLoad completion-nvim ale\n```\n\nYou can configure Neovim to automatically run `:PackerCompile` whenever `plugins.lua` is updated with\n[an autocommand](https://neovim.io/doc/user/autocmd.html#:autocmd):\n\n```\naugroup packer_user_config\n  autocmd!\n  autocmd BufWritePost plugins.lua source <afile> | PackerCompile\naugroup end\n```\n\nThis autocommand can be placed in your `init.vim`, or any other startup file as per your setup.\nPlacing this in `plugins.lua` could look like this:\n\n```lua\nvim.cmd([[\n  augroup packer_user_config\n    autocmd!\n    autocmd BufWritePost plugins.lua source <afile> | PackerCompile\n  augroup end\n]])\n```\n\n## Bootstrapping\n\nIf you want to automatically install and set up `packer.nvim` on any machine you clone your configuration to,\nadd the following snippet (which is due to @Iron-E and @khuedoan) somewhere in your config **before** your first usage of `packer`:\n\n```lua\nlocal ensure_packer = function()\n  local fn = vim.fn\n  local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim'\n  if fn.empty(fn.glob(install_path)) > 0 then\n    fn.system({'git', 'clone', '--depth', '1', 'https://github.com/wbthomason/packer.nvim', install_path})\n    vim.cmd [[packadd packer.nvim]]\n    return true\n  end\n  return false\nend\n\nlocal packer_bootstrap = ensure_packer()\n\nreturn require('packer').startup(function(use)\n  use 'wbthomason/packer.nvim'\n  -- My plugins here\n  -- use 'foo1/bar1.nvim'\n  -- use 'foo2/bar2.nvim'\n\n  -- Automatically set up your configuration after cloning packer.nvim\n  -- Put this at the end after all plugins\n  if packer_bootstrap then\n    require('packer').sync()\n  end\nend)\n```\n\nYou can also use the following command (with `packer` bootstrapped) to have `packer` setup your\nconfiguration (or simply run updates) and close once all operations are completed:\n\n```sh\n$ nvim --headless -c 'autocmd User PackerComplete quitall' -c 'PackerSync'\n```\n\n## Usage\n\nThe above snippets give some examples of `packer` features and use. Examples include:\n\n- My dotfiles:\n  - [Specification file](https://github.com/wbthomason/dotfiles/blob/linux/neovim/.config/nvim/lua/plugins.lua)\n  - [Loading file](https://github.com/wbthomason/dotfiles/blob/linux/neovim/.config/nvim/lua/plugins.lua)\n  - [Generated lazy-loader file](https://github.com/wbthomason/dotfiles/blob/linux/neovim/.config/nvim/plugin/packer_compiled.lua)\n- An example using the `startup` method: [tjdevries](https://github.com/tjdevries/config_manager/blob/master/xdg_config/nvim/lua/tj/plugins.lua)\n    - Using this method, you do not require a \"loading\" file. You can simply `lua require('plugins')` from your `init.vim`\n\nThe following is a more in-depth explanation of `packer`'s features and use.\n\n### The `startup` function\n`packer` provides `packer.startup(spec)`, which is used in the above examples.\n\n`startup` is a convenience function for simple setup and can be invoked as follows:\n- `spec` can be a function: `packer.startup(function() use 'tjdevries/colorbuddy.vim' end)`\n- `spec` can be a table with a function as its first element and config overrides as another element:\n  `packer.startup({function() use 'tjdevries/colorbuddy.vim' end, config = { ... }})`\n- `spec` can be a table with a table of plugin specifications as its first element, config overrides as another element, and optional rock specifications as another element:\n `packer.startup({{'tjdevries/colorbuddy.vim'}, config = { ... }, rocks = { ... }})`\n\n### Custom Initialization\nYou are not required to use `packer.startup` if you prefer a more manual setup with finer control\nover configuration and loading.\n\nTo take this approach, load `packer` like any other Lua module. You must call `packer.init()` before\nperforming any operations; it is recommended to call `packer.reset()` if you may be re-running your\nspecification code (e.g. by sourcing your plugin specification file with `luafile`).\n\nYou may pass a table of configuration values to `packer.init()` to customize its operation. The\ndefault configuration values (and structure of the configuration table) are:\n```lua\nlocal packer = require('packer')\npacker.util = require('packer.util')\n\npacker.init({\n  ensure_dependencies = true, -- Should packer install plugin dependencies?\n  snapshot = nil, -- Name of the snapshot you would like to load at startup\n  snapshot_path = packer.util.join_paths(vim.fn.stdpath('cache'), 'packer.nvim'), -- Default save directory for snapshots\n  package_root  = packer.util.join_paths(vim.fn.stdpath('data'), 'site', 'pack'),\n  compile_path  = packer.util.join_paths(vim.fn.stdpath('config'), 'plugin', 'packer_compiled.lua'),\n  plugin_package = 'packer', -- The default package for plugins\n  max_jobs = nil, -- Limit the number of simultaneous jobs. nil means no limit\n  auto_clean = true, -- During sync(), remove unused plugins\n  compile_on_sync = true, -- During sync(), run packer.compile()\n  disable_commands = false, -- Disable creating commands\n  opt_default = false, -- Default to using opt (as opposed to start) plugins\n  transitive_opt = true, -- Make dependencies of opt plugins also opt by default\n  transitive_disable = true, -- Automatically disable dependencies of disabled plugins\n  auto_reload_compiled = true, -- Automatically reload the compiled file after creating it.\n  preview_updates = false, -- If true, always preview updates before choosing which plugins to update, same as `PackerUpdate --preview`.\n  git = {\n    cmd = 'git', -- The base command for git operations\n    subcommands = { -- Format strings for git subcommands\n      update         = 'pull --ff-only --progress --rebase=false --force',\n      install        = 'clone --depth %i --no-single-branch --progress',\n      fetch          = 'fetch --depth 999999 --progress --force',\n      checkout       = 'checkout %s --',\n      update_branch  = 'merge --ff-only @{u}',\n      current_branch = 'branch --show-current',\n      diff           = 'log --color=never --pretty=format:FMT --no-show-signature HEAD@{1}...HEAD',\n      diff_fmt       = '%%h %%s (%%cr)',\n      get_rev        = 'rev-parse --short HEAD',\n      get_msg        = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1',\n      submodules     = 'submodule update --init --recursive --progress'\n    },\n    depth = 1, -- Git clone depth\n    clone_timeout = 60, -- Timeout, in seconds, for git clones\n    default_url_format = 'https://github.com/%s' -- Lua format string used for \"aaa/bbb\" style plugins\n  },\n  display = {\n    non_interactive = false, -- If true, disable display windows for all operations\n    compact = false, -- If true, fold updates results by default\n    open_fn  = nil, -- An optional function to open a window for packer's display\n    open_cmd = '65vnew \\\\[packer\\\\]', -- An optional command to open a window for packer's display\n    working_sym = '⟳', -- The symbol for a plugin being installed/updated\n    error_sym = '✗', -- The symbol for a plugin with an error in installation/updating\n    done_sym = '✓', -- The symbol for a plugin which has completed installation/updating\n    removed_sym = '-', -- The symbol for an unused plugin which was removed\n    moved_sym = '→', -- The symbol for a plugin which was moved (e.g. from opt to start)\n    header_sym = '━', -- The symbol for the header line in packer's display\n    show_all_info = true, -- Should packer show all update details automatically?\n    prompt_border = 'double', -- Border style of prompt popups.\n    keybindings = { -- Keybindings for the display window\n      quit = 'q',\n      toggle_update = 'u', -- only in preview\n      continue = 'c', -- only in preview\n      toggle_info = '<CR>',\n      diff = 'd',\n      prompt_revert = 'r',\n    }\n  },\n  luarocks = {\n    python_cmd = 'python' -- Set the python command to use for running hererocks\n  },\n  log = { level = 'warn' }, -- The default print log level. One of: \"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\".\n  profile = {\n    enable = false,\n    threshold = 1, -- integer in milliseconds, plugins which load faster than this won't be shown in profile output\n  },\n  autoremove = false, -- Remove disabled or unused plugins without prompting the user\n})\n```\n\n### Specifying plugins\n\n`packer` is based around declarative specification of plugins. You can declare a plugin using the\nfunction `packer.use`, which I highly recommend locally binding to `use` for conciseness.\n\n`use` takes either a string or a table. If a string is provided, it is treated as a plugin location\nfor a non-optional plugin with no additional configuration. Plugin locations may be specified as\n\n1. Absolute paths to a local plugin\n2. Full URLs (treated as plugins managed with `git`)\n3. `username/repo` paths (treated as Github `git` plugins)\n\nA table given to `use` can take two forms:\n\n1. A list of plugin specifications (strings or tables)\n2. A table specifying a single plugin. It must have a plugin location string as its first element,\n   and may additionally have a number of optional keyword elements, shown below:\n```lua\nuse {\n  'myusername/example',        -- The plugin location string\n  -- The following keys are all optional\n  disable = boolean,           -- Mark a plugin as inactive\n  as = string,                 -- Specifies an alias under which to install the plugin\n  installer = function,        -- Specifies custom installer. See \"custom installers\" below.\n  updater = function,          -- Specifies custom updater. See \"custom installers\" below.\n  after = string or list,      -- Specifies plugins to load before this plugin. See \"sequencing\" below\n  rtp = string,                -- Specifies a subdirectory of the plugin to add to runtimepath.\n  opt = boolean,               -- Manually marks a plugin as optional.\n  bufread = boolean,           -- Manually specifying if a plugin needs BufRead after being loaded\n  branch = string,             -- Specifies a git branch to use\n  tag = string,                -- Specifies a git tag to use. Supports '*' for \"latest tag\"\n  commit = string,             -- Specifies a git commit to use\n  lock = boolean,              -- Skip updating this plugin in updates/syncs. Still cleans.\n  run = string, function, or table, -- Post-update/install hook. See \"update/install hooks\".\n  requires = string or list,   -- Specifies plugin dependencies. See \"dependencies\".\n  rocks = string or list,      -- Specifies Luarocks dependencies for the plugin\n  config = string or function, -- Specifies code to run after this plugin is loaded.\n  -- The setup key implies opt = true\n  setup = string or function,  -- Specifies code to run before this plugin is loaded. The code is ran even if\n                               -- the plugin is waiting for other conditions (ft, cond...) to be met.\n  -- The following keys all imply lazy-loading and imply opt = true\n  cmd = string or list,        -- Specifies commands which load this plugin. Can be an autocmd pattern.\n  ft = string or list,         -- Specifies filetypes which load this plugin.\n  keys = string or list,       -- Specifies maps which load this plugin. See \"Keybindings\".\n  event = string or list,      -- Specifies autocommand events which load this plugin.\n  fn = string or list          -- Specifies functions which load this plugin.\n  cond = string, function, or list of strings/functions,   -- Specifies a conditional test to load this plugin\n  module = string or list      -- Specifies Lua module names for require. When requiring a string which starts\n                               -- with one of these module names, the plugin will be loaded.\n  module_pattern = string/list -- Specifies Lua pattern of Lua module names for require. When\n                               -- requiring a string which matches one of these patterns, the plugin will be loaded.\n}\n```\n\nFor the `cmd` option, the command may be a full command, or an autocommand pattern. If the command contains any\nnon-alphanumeric characters, it is assumed to be a pattern, and instead of creating a stub command, it creates\na CmdUndefined autocmd to load the plugin when a command that matches the pattern is invoked.\n\n#### Checking plugin statuses\nYou can check whether or not a particular plugin is installed with `packer` as well as if that plugin is loaded.\nTo do this you can check for the plugin's name in the `packer_plugins` global table.\nPlugins in this table are saved using only the last section of their names\ne.g. `tpope/vim-fugitive` if installed will be under the key `vim-fugitive`.\n\n```lua\nif packer_plugins[\"vim-fugitive\"] and packer_plugins[\"vim-fugitive\"].loaded then\nprint(\"Vim fugitive is loaded\")\n-- other custom logic\nend\n```\n**NOTE:** this table is only available *after* `packer_compiled.vim` is loaded so cannot be used till *after* plugins\nhave been loaded.\n\n#### Luarocks support\n\nYou may specify that a plugin requires one or more Luarocks packages using the `rocks` key. This key\ntakes either a string specifying the name of a package (e.g. `rocks=lpeg`), or a list specifying one or more packages.\nEntries in the list may either be strings, a list of strings or a table --- the latter case is used to specify arguments such as the\nparticular version of a package.\nall supported luarocks keys are allowed except: `tree` and `local`. Environment variables for the luarocks command can also be\nspecified using the `env` key which takes a table as the value as shown below.\n```lua\nrocks = {'lpeg', {'lua-cjson', version = '2.1.0'}}\nuse_rocks {'lua-cjson', 'lua-resty-http'}\nuse_rocks {'luaformatter', server = 'https://luarocks.org/dev'}\nuse_rocks {'openssl' env = {OPENSSL_DIR = \"/path/to/dir\"}}\n```\n\nCurrently, `packer` only supports equality constraints on package versions.\n\n`packer` also provides the function `packer.luarocks.install_commands()`, which creates the\n`PackerRocks <cmd> <packages...>` command. `<cmd>` must be one of \"install\" or \"remove\";\n`<packages...>` is one or more package names (currently, version restrictions are not supported with\nthis command). Running `PackerRocks` will install or remove the given packages. You can use this\ncommand even if you don't use `packer` to manage your plugins. However, please note that (1)\npackages installed through `PackerRocks` **will** be removed by calls to `packer.luarocks.clean()`\n(unless they are also part of a `packer` plugin specification), and (2) you will need to manually\ninvoke `packer.luarocks.setup_paths` (or otherwise modify your `package.path`) to ensure that Neovim\ncan find the installed packages.\n\nFinally, `packer` provides the function `packer.use_rocks`, which takes a string or table specifying\none or more Luarocks packages as in the `rocks` key. You can use this to ensure that `packer`\ndownloads and manages some rocks which you want to use, but which are not associated with any\nparticular plugin.\n\n#### Custom installers\n\nYou may specify a custom installer & updater for a plugin using the `installer` and `updater` keys.\nNote that either both or none of these keys are required. These keys should be functions which take\nas an argument a `display` object (from `lua/packer/display.lua`) and return an async function (per\n`lua/packer/async.lua`) which (respectively) installs/updates the given plugin.\n\nProviding the `installer`/`updater` keys overrides plugin type detection, but you still need to\nprovide a location string for the name of the plugin.\n\n#### Update/install hooks\n\nYou may specify operations to be run after successful installs/updates of a plugin with the `run`\nkey. This key may either be a Lua function, which will be called with the `plugin` table for this\nplugin (containing the information passed to `use` as well as output from the installation/update\ncommands, the installation path of the plugin, etc.), a string, or a table of functions and strings.\n\nIf an element of `run` is a string, then either:\n\n1. If the first character of `run` is \":\", it is treated as a Neovim command and executed.\n2. Otherwise, `run` is treated as a shell command and run in the installation directory of the\n   plugin via `$SHELL -c '<run>'`.\n\n#### Dependencies\n\nPlugins may specify dependencies via the `requires` key. This key can be a string or a list (table).\n\nIf `requires` is a string, it is treated as specifying a single plugin. If a plugin with the name\ngiven in `requires` is already known in the managed set, nothing happens. Otherwise, the string is\ntreated as a plugin location string and the corresponding plugin is added to the managed set.\n\nIf `requires` is a list, it is treated as a list of plugin specifications following the format given\nabove.\n\nIf `ensure_dependencies` is true, the plugins specified in `requires` will be installed.\n\nPlugins specified in `requires` are removed when no active plugins require them.\n\n#### Sequencing\n\nYou may specify a loading order for plugins using the `after` key. This key can be a string or a\nlist (table).\n\nIf `after` is a string, it must be the name of another plugin managed by `packer` (e.g. the final segment of a plugin's path - for a Github plugin `FooBar/Baz`, the name would be just `Baz`). If `after` is a table, it must be a list of plugin names. If a plugin has an alias (i.e. uses the `as` key), this alias is its name.\n\nThe set of plugins specified in a plugin's `after` key must **all** be loaded before the plugin\nusing `after` will be loaded. For example, in the specification\n```lua\n  use {'FooBar/Baz', ft = 'bax'}\n  use {'Something/Else', after = 'Baz'}\n```\nthe plugin `Else` will only be loaded after the plugin `Baz`, which itself is only loaded for files\nwith `bax` filetype.\n\n#### Keybindings\n\nPlugins may be lazy-loaded on the use of keybindings/maps. Individual keybindings are specified either as a string (in which case they are treated as normal mode maps) or a table in the format `{mode, map}`.\n\n### Performing plugin management operations\n`packer` exposes the following functions for common plugin management operations. In all of the\nbelow, `plugins` is an optional table of plugin names; if not provided, the default is \"all managed\nplugins\":\n\n- `packer.install(plugins)`: Install the specified plugins if they are not already installed\n- `packer.update(plugins)`: Update the specified plugins, installing any that are missing\n- `packer.update(opts, plugins)`: First argument can be a table specifying options, such as `{preview_updates = true}` to preview potential changes before updating (same as `PackerUpdate --preview`).\n- `packer.clean()`: Remove any disabled or no longer managed plugins\n- `packer.sync(plugins)`: Perform a `clean` followed by an `update`.\n- `packer.sync(opts, plugins)`: Can take same optional options as `update`.\n- `packer.compile(path)`: Compile lazy-loader code and save to `path`.\n- `packer.snapshot(snapshot_name, ...)`: Creates a snapshot file that will live under `config.snapshot_path/<snapshot_name>`. If `snapshot_name` is an absolute path, then that will be the location where the snapshot will be taken. Optionally, a list of plugins name can be provided to selectively choose the plugins to snapshot.\n- `packer.rollback(snapshot_name, ...)`: Rollback plugins status a snapshot file that will live under `config.snapshot_path/<snapshot_name>`. If `snapshot_name` is an absolute path, then that will be the location where the snapshot will be taken. Optionally, a list of plugins name can be provided to selectively choose which plugins to revert.\n- `packer.delete(snapshot_name)`: Deletes a snapshot file under `config.snapshot_path/<snapshot_name>`. If `snapshot_name` is an absolute path, then that will be the location where the snapshot will be deleted.\n\n### Extending `packer`\nYou can add custom key handlers to `packer` by calling `packer.set_handler(name, func)` where `name`\nis the key you wish to handle and `func` is a function with the signature `func(plugins, plugin,\nvalue)` where `plugins` is the global table of managed plugins, `plugin` is the table for a specific\nplugin, and `value` is the value associated with key `name` in `plugin`.\n\n### Compiling Lazy-Loaders\nTo optimize startup time, `packer.nvim` compiles code to perform the lazy-loading operations you\nspecify. This means that you do not need to load `packer.nvim` unless you want to perform some\nplugin management operations.\n\nTo generate the compiled code, call `packer.compile(path)`, where `path` is some file path on your\n`runtimepath`, with a `.vim` extension. This will generate a blend of Lua and Vimscript to load and\nconfigure all your lazy-loaded plugins (e.g. generating commands, autocommands, etc.) and save it to\n`path`. Then, when you start vim, the file at `path` is loaded (because `path` must be on your\n`runtimepath`), and lazy-loading works.\n\nIf `path` is not provided to `packer.compile`, the output file will default to the value of\n`config.compile_path`.\n\nThe option `compile_on_sync`, which defaults to `true`, will run `packer.compile()` during\n`packer.sync()`, if set to `true`. Note that otherwise, you **must** run `packer.compile` yourself\nto generate the lazy-loader file!\n\n**NOTE:** If you use a function value for `config` or `setup` keys in any plugin specifications, it\n**must not** have any upvalues (i.e. captures). We currently use Lua's `string.dump` to compile\nconfig/setup functions to bytecode, which has this limitation.\nAdditionally, if functions are given for these keys, the functions will be passed the plugin\nname and information table as arguments.\n\n### User autocommands\n`packer` runs most of its operations asyncronously. If you would like to implement automations that\nrequire knowing when the operations are complete, you can use the following `User` autocmds (see\n`:help User` for more info on how to use):\n\n- `PackerComplete`: Fires after install, update, clean, and sync asynchronous operations finish.\n- `PackerCompileDone`: Fires after compiling (see [the section on compilation](#compiling-lazy-loaders))\n\n### Using a floating window\nYou can configure Packer to use a floating window for command outputs by passing a utility\nfunction to `packer`'s config:\n```lua\npacker.startup({function()\n  -- Your plugins here\nend,\nconfig = {\n  display = {\n    open_fn = require('packer.util').float,\n  }\n}})\n```\n\nBy default, this floating window will show doubled borders. If you want to customize the window\nappearance, you can pass a configuration to `float`, which is the same configuration that would be\npassed to `nvim_open_win`:\n```lua\npacker.startup({function()\n  -- Your plugins here\nend,\nconfig = {\n  display = {\n    open_fn = function()\n      return require('packer.util').float({ border = 'single' })\n    end\n  }\n}})\n```\n\n## Profiling\nPacker has built in functionality that can allow you to profile the time taken loading your plugins.\nIn order to use this functionality you must either enable profiling in your config, or pass in an argument\nwhen running packer compile.\n\n#### Setup via config\n```lua\nconfig = {\n  profile = {\n    enable = true,\n    threshold = 1 -- the amount in ms that a plugin's load time must be over for it to be included in the profile\n  }\n}\n```\n\n#### Using the packer compile command\n```vim\n:PackerCompile profile=true\n\" or\n:PackerCompile profile=false\n```\n\n#### Profiling usage\nThis will rebuild your `packer_compiled.vim` with profiling code included. In order to visualise the output of the profile\nrestart your neovim and run `PackerProfile`. This will open a window with the output of your profiling.\n\n## Debugging\n`packer.nvim` logs to `stdpath(cache)/packer.nvim.log`. Looking at this file is usually a good start\nif something isn't working as expected.\n\n## Compatibility and known issues\n\n- **2021-07-31:** If you're on macOS, note that building Neovim with the version of `luv` from `homebrew` [will cause any `packer` command to crash](https://github.com/wbthomason/packer.nvim/issues/496#issuecomment-890371022). More about this issue at [neovim/neovim#15054](https://github.com/neovim/neovim/issues/15054).\n- **2021-07-28:** `packer` will now highlight commits/plugin names with potentially breaking changes\n  (determined by looking for `breaking change` or `breaking_change`, case insensitive, in the update\n  commit bodies and headers) as `WarningMsg` in the status window.\n- **2021-06-06**: Your Neovim must include https://github.com/neovim/neovim/pull/14659; `packer` uses the `noautocmd` key.\n- **2021-04-19**: `packer` now provides built-in profiling for your config via the `packer_compiled`\n  file. Take a look at [the docs](#profiling) for more information!\n- **2021-02-18**: Having trouble with Luarocks on macOS? See [this issue](https://github.com/wbthomason/packer.nvim/issues/180).\n- **2021-01-19**: Basic Luarocks support has landed! Use the `rocks` key with a string or table to specify packages to install.\n- **2020-12-10**: The `disable_commands` configuration flag now affects non-`startup` use as well. This means that, by default, `packer` will create commands for basic operations for you.\n- **2020-11-13**: There is now a default implementation for a floating window `open_fn` in `packer.util`.\n- **2020-09-04:** Due to changes to the Neovim `extmark` api (see: https://github.com/neovim/neovim/commit/3853276d9cacc99a2698117e904475dbf7033383), users will need to update to a version of Neovim **after** the aforementioned PR was merged. There are currently shims around the changed functions which should maintain support for earlier versions of Neovim, but these are intended to be temporary and will be removed by **2020-10-04**. Therefore Packer will not work with Neovim v0.4.4, which was released before the `extmark` change.\n\n## Contributors\nMany thanks to those who have contributed to the project! PRs and issues are always welcome. This\nlist is infrequently updated; please feel free to bug me if you're not listed here and you would\nlike to be.\n\n- [@akinsho](https://github.com/akinsho)\n- [@nanotee](https://github.com/nanotee)\n- [@weilbith](https://github.com/weilbith)\n- [@Iron-E](https://github.com/Iron-E)\n- [@tjdevries](https://github.com/tjdevries)\n- [@numToStr](https://github.com/numToStr)\n- [@fsouza](https://github.com/fsouza)\n- [@gbrlsnchs](https://github.com/gbrlsnchs)\n- [@lewis6991](https://github.com/lewis6991)\n- [@TimUntersberger](https://github.com/TimUntersberger)\n- [@bfredl](https://github.com/bfredl)\n- [@sunjon](https://github.com/sunjon)\n- [@gwerbin](https://github.com/gwerbin)\n- [@shadmansaleh](https://github.com/shadmansaleh)\n- [@ur4ltz](https://github.com/ur4ltz)\n- [@EdenEast](https://github.com/EdenEast)\n- [@khuedoan](https://github.com/khuedoan)\n- [@kevinhwang91](https://github.com/kevinhwang91)\n- [@runiq](https://github.com/runiq)\n- [@n3wborn](https://github.com/n3wborn)\n- [@deathlyfrantic](https://github.com/deathlyfrantic)\n- [@doctoromer](https://github.com/doctoromer)\n- [@elianiva](https://github.com/elianiva)\n- [@dundargoc](https://github.com/dundargoc)\n- [@jdelkins](https://github.com/jdelkins)\n- [@dsully](https://github.com/dsully)\n"
  },
  {
    "path": "doc/packer.txt",
    "content": "*packer.txt*                      A use-package inspired Neovim plugin manager\n*packer.nvim*\n\nAuthor: Wil Thomason <wil.thomason@gmail.com>\n\nCONTENTS                                        *packer-contents*\nIntroduction                                    |packer-introduction|\n  Features                                      |packer-intro-features|\n  Requirements                                  |packer-intro-requirements|\n  Quickstart                                    |packer-intro-quickstart|\nUsage                                           |packer-usage|\nAPI                                             |packer-api|\n==============================================================================\nINTRODUCTION                                    *packer-introduction*\n\nThis is a Neovim plugin manager. It is written in Lua, uses the native\n|packages| feature, and has features for declarative plugin configuration\ninspired by the `use-package` library from Emacs.\n\n==============================================================================\nREQUIREMENTS                                     *packer-intro-requirements*\n\n- You need to be running Neovim v0.5.0+; `packer` makes use of extmarks and\n  other newly-added Neovim features.\n- Your version of Neovim must be compiled with LuaJIT support; `packer` relies\n  on this to detect whether you are running Windows or a Unix-like OS (for path\n  separators)\n- If you are on Windows 10, you need developer mode enabled in order to use\n  local plugins (creating symbolic links requires admin privileges on Windows\n  - credit to @TimUntersberger for this note)\n\n==============================================================================\nFEATURES                                         *packer-intro-features*\n\n- Declarative plugin specification\n- Support for dependencies\n- Support for Luarocks dependencies\n- Expressive configuration and lazy-loading options\n- Automatically compiles efficient lazy-loading code to improve startup time\n- Uses native packages\n- Extensible\n- Written in Lua, configured in Lua\n- Post-install/update hooks\n- Uses jobs for async installation\n- Support for `git` tags, branches, revisions, submodules\n- Support for local plugins\n- Support for saving/restoring snapshots for plugin versions (`git` only)\n\n==============================================================================\nQUICKSTART                                       *packer-intro-quickstart*\n\nTo get started, first clone this repository to somewhere on your `packpath`, e.g.: >sh\n  git clone https://github.com/wbthomason/packer.nvim\\\n   ~/.local/share/nvim/site/pack/packer/opt/packer.nvim\n\n\nThen you can write your plugin specification in Lua, e.g. (in `~/.config/nvim/lua/plugins.lua`): >lua\n\n  -- This file can be loaded by calling `lua require('plugins')` from your init.vim\n\n  -- Only required if you have packer in your `opt` pack\n  vim.cmd [[packadd packer.nvim]]\n  -- Only if your version of Neovim doesn't have https://github.com/neovim/neovim/pull/12632 merged\n  vim._update_package_paths()\n\n  return require('packer').startup(function()\n    -- Packer can manage itself as an optional plugin\n    use {'wbthomason/packer.nvim', opt = true}\n\n    -- Simple plugins can be specified as strings\n    use '9mm/vim-closer'\n\n    -- Lazy loading:\n    -- Load on specific commands\n    use {'tpope/vim-dispatch', opt = true, cmd = {'Dispatch', 'Make', 'Focus', 'Start'}}\n\n    -- Load on an autocommand event\n    use {'andymass/vim-matchup', event = 'VimEnter *'}\n\n    -- Load on a combination of conditions: specific filetypes or commands\n    -- Also run code after load (see the \"config\" key)\n    use {\n      'w0rp/ale',\n      ft = {'sh', 'zsh', 'bash', 'c', 'cpp', 'cmake', 'html', 'markdown', 'racket', 'vim', 'tex'},\n      cmd = 'ALEEnable',\n      config = 'vim.cmd[[ALEEnable]]'\n    }\n\n    -- Plugins can have dependencies on other plugins\n    use {\n      'haorenW1025/completion-nvim',\n      opt = true,\n      requires = {{'hrsh7th/vim-vsnip', opt = true}, {'hrsh7th/vim-vsnip-integ', opt = true}}\n    }\n\n    -- Local plugins can be included\n    use '~/projects/personal/hover.nvim'\n\n    -- Plugins can have post-install/update hooks\n    use {'iamcco/markdown-preview.nvim', run = 'cd app && yarn install', cmd = 'MarkdownPreview'}\n\n    -- You can specify multiple plugins in a single call\n    use {'tjdevries/colorbuddy.vim', {'nvim-treesitter/nvim-treesitter', opt = true}}\n\n    -- You can alias plugin names\n    use {'dracula/vim', as = 'dracula'}\n  end)\n\n`packer` provides the following commands after you've run and configured `packer` with `require('packer').startup(...)`: *packer-default-commands* *packer-commands*\n\n`PackerClean`                                   *packer-commands-clean*\nRemove any disabled or unused plugins.\n\n`PackerCompile`                                 *packer-commands-compile*\nYou must run this or `PackerSync` whenever you make changes to your plugin\nconfiguration. Regenerate compiled loader file.\n\n`PackerInstall`                                 *packer-commands-install*\nClean, then install missing plugins.\n\n`PackerUpdate`                                  *packer-commands-update*\nClean, then update and install plugins.\nSupports the `--preview` flag as an optional first argument to preview\nupdates.\n\n`PackerSync`                                    *packer-commands-sync*\nPerform `PackerUpdate` and then `PackerCompile`.\nSupports the `--preview` flag as an optional first argument to preview\nupdates.\n\n`PackerLoad`                                    *packer-commands-load*\nLoads opt plugin immediately\n\n`PackerSnapshot`                                    *packer-commands-snapshot*\nSnapshots your plugins to a file\n\n`PackerSnapshotDelete`                                    *packer-commands-delete*\nDeletes a snapshot\n\n`PackerSnapshotRollback`                                    *packer-commands-rollback*\nRolls back plugins' commit specified by the snapshot\n==============================================================================\nUSAGE                                          *packer-usage*\n\nAlthough the example in |packer-intro-quickstart| will be enough to get you\ngoing for basic usage, `packer` has a number of other features and options\ndetailed in this section.\n\nSTARTUP                                        *packer-startup*\n\nThe easiest way to use `packer` is via the |packer.startup()| function. In\nshort, `startup` is a convenience function for simple setup, and is invoked as\n`packer.startup(spec)`, where:\n\n- `spec` can be a function: >lua\n  packer.startup(function() use 'tjdevries/colorbuddy.vim' end)\n- `spec` can be a table with a function as its first element and config\n  overrides as another element: >lua\n  packer.startup({\n    function() use 'tjdevries/colorbuddy.vim' end, config = { ... }\n    })\n- `spec` can be a table with a table of plugin specifications as its first\n  element, config overrides as another element, and optional rock\n  specifications as another element: >lua\n  packer.startup({{'tjdevries/colorbuddy.vim'}, config = { ... }, rocks = { ... }})\n\nSee |packer-configuration| for the allowed configuration keys.\n\n`startup` will handle calling |packer.init()| and |packer.reset()| for you, as\nwell as creating the commands given in |packer-commands|.\n\nCUSTOM INITIALIZATION                          *packer-custom-initialization*\nIf you prefer a more manual setup with finer control over configuration and\nloading, you may use custom initialization for `packer`. This approach has the\nbenefit of not requiring that the `packer` plugin be loaded unless you want to\nperform plugin management operations, but it is more involved to use.\n\nTo take this approach, load `packer` like any other Lua module. You must call\n|packer.init()| before performing any operations; it is recommended to call\n|packer.reset()| if you may be re-running your specification code (e.g. by\nsourcing your plugin specification file with `luafile`).\n\nSee |packer.init()| for more details on initialization; in short, `init` takes\na table of configuration values like that which can be passed to `startup`.\n\nIf you use custom initialization, you'll probably want to define commands to\nload `packer` and perform common package management operations. The following\ncommands work well for this purpose: >vim\n\n  command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete  PackerInstall lua require('packer').install(<f-args>)\n  command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerUpdate lua require('packer').update(<f-args>)\n  command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerSync lua require('packer').sync(<f-args>)\n  command! PackerClean packadd packer.nvim | lua require('plugins').clean()\n  command! PackerCompile packadd packer.nvim | lua require('plugins').compile('~/.config/nvim/plugin/packer_load.vim')\n  command! -bang -nargs=+ -complete=customlist,v:lua.require'packer'.loader_complete PackerLoad lua require('packer').loader(<f-args>, '<bang>')\n\nCONFIGURATION                                  *packer-configuration*\n`packer` provides the following configuration variables, presented in the\nstructure of the `config` table expected by `startup` or `init`, with their\ndefault values: >lua\n  {\n    ensure_dependencies   = true, -- Should packer install plugin dependencies?\n    package_root   = util.join_paths(vim.fn.stdpath('data'), 'site', 'pack'),\n    compile_path = util.join_paths(vim.fn.stdpath('config'), 'plugin', 'packer_compiled.lua'),\n    plugin_package = 'packer', -- The default package for plugins\n    max_jobs = nil, -- Limit the number of simultaneous jobs. nil means no limit\n    auto_clean = true, -- During sync(), remove unused plugins\n    compile_on_sync = true, -- During sync(), run packer.compile()\n    disable_commands = false, -- Disable creating commands\n    opt_default = false, -- Default to using opt (as opposed to start) plugins\n    transitive_opt = true, -- Make dependencies of opt plugins also opt by default\n    transitive_disable = true, -- Automatically disable dependencies of disabled plugins\n    auto_reload_compiled = true, -- Automatically reload the compiled file after creating it.\n    preview_updates = false, -- If true, always preview updates before choosing which plugins to update, same as `PackerUpdate --preview`.\n    git = {\n      cmd = 'git', -- The base command for git operations\n      subcommands = { -- Format strings for git subcommands\n        update         = 'pull --ff-only --progress --rebase=false --force',\n        install        = 'clone --depth %i --no-single-branch --progress',\n        fetch          = 'fetch --depth 999999 --progress --force',\n        checkout       = 'checkout %s --',\n        update_branch  = 'merge --ff-only @{u}',\n        current_branch = 'branch --show-current',\n        diff           = 'log --color=never --pretty=format:FMT --no-show-signature HEAD@{1}...HEAD',\n        diff_fmt       = '%%h %%s (%%cr)',\n        get_rev        = 'rev-parse --short HEAD',\n        get_msg        = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1',\n        submodules     = 'submodule update --init --recursive --progress'\n      },\n      depth = 1, -- Git clone depth\n      clone_timeout = 60, -- Timeout, in seconds, for git clones\n      default_url_format = 'https://github.com/%s' -- Lua format string used for \"aaa/bbb\" style plugins\n    },\n    log = { level = 'warn' }, -- The default print log level. One of: \"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\".\n    display = {\n      non_interactive = false, -- If true, disable display windows for all operations\n      compact = false, -- If true, fold updates results by default\n      open_fn  = nil, -- An optional function to open a window for packer's display\n      open_cmd = '65vnew \\\\[packer\\\\]', -- An optional command to open a window for packer's display\n      working_sym = '⟳', -- The symbol for a plugin being installed/updated\n      error_sym = '✗', -- The symbol for a plugin with an error in installation/updating\n      done_sym = '✓', -- The symbol for a plugin which has completed installation/updating\n      removed_sym = '-', -- The symbol for an unused plugin which was removed\n      moved_sym = '→', -- The symbol for a plugin which was moved (e.g. from opt to start)\n      header_sym = '━', -- The symbol for the header line in packer's display\n      show_all_info = true, -- Should packer show all update details automatically?\n      prompt_border = 'double', -- Border style of prompt popups.\n      keybindings = { -- Keybindings for the display window\n        quit = 'q',\n        toggle_update = 'u', -- only in preview\n        continue = 'c', -- only in preview\n        toggle_info = '<CR>',\n        diff = 'd',\n        prompt_revert = 'r',\n      }\n    }\n    autoremove = false, -- Remove disabled or unused plugins without prompting the user\n  }\n\nSPECIFYING PLUGINS                             *packer-specifying-plugins*\n`packer` is based around declarative specification of plugins. You can declare\na plugin using the function |packer.use()|, which I highly recommend locally\nbinding to `use` for conciseness.\n\n`use` takes either a string or a table. If a string is provided, it is treated\nas a plugin location for a non-optional plugin with no additional\nconfiguration. Plugin locations may be specified as:\n  1. Absolute paths to a local plugin\n  2. Full URLs (treated as plugins managed with `git`)\n  3. `username/repo` paths (treated as Github `git` plugins)\n\nA table given to `use` can take two forms:\n  1. A list of plugin specifications (strings or tables)\n  2. A table specifying a single plugin. It must have a plugin location string\n  as its first element, and may additionally have a number of optional keyword\n  elements, detailed in |packer.use()|\n\nCONFIGURING PLUGINS                            *packer-plugin-configuration*\n`packer` allows you to configure plugins either before they are loaded (the\n`setup` key described in |packer.use()|) or after they are loaded (the\n`config` key described in |packer.use()|).\nIf functions are given for these keys, the functions will be passed the plugin\nname and information table as arguments.\n\nPLUGIN STATUSES                                 *packer-plugin-status*\nYou can check whether or not a particular plugin is installed with `packer` as\nwell as if that plugin is loaded. To do this you can check for the plugin's\nname in the `packer_plugins` global table. Plugins in this table are saved\nusing only the last section of their names e.g. `tpope/vim-fugitive` if\ninstalled will be under the key `vim-fugitive`.\n>lua\n  if packer_plugins[\"vim-fugitive\"] and packer_plugins[\"vim-fugitive\"].loaded then\n  print(\"Vim fugitive is loaded\")\n  -- other custom logic\n  end\n\nCUSTOM INSTALLERS                              *packer-custom-installers*\nYou may specify a custom installer & updater for a plugin using the\n`installer` and `updater` keys in a plugin specification. Note that either\nboth or none of these keys are required. These keys should be functions which\ntake as an argument a `display` object (from `lua/packer/display.lua`) and\nreturn an async function (per `lua/packer/async.lua`) which (respectively)\ninstalls/updates the given plugin.\n\nProviding the `installer`/`updater` keys overrides plugin type detection, but\nyou still need to provide a location string for the name of the plugin.\n\nPOST-UPDATE HOOKS                              *packer-plugin-hooks*\nYou may specify operations to be run after successful installs/updates of a\nplugin with the `run` key. This key may either be a Lua function, which will be\ncalled with the `plugin` table for this plugin (containing the information\npassed to `use` as well as output from the installation/update commands, the\ninstallation path of the plugin, etc.), a string, or a table of functions and\nstrings.\n\nIf an element of `run` is a string, then either:\n\n1. If the first character of `run` is \":\", it is treated as a Neovim command and\nexecuted.\n2. Otherwise, `run` is treated as a shell command and run in the installation\ndirectory of the plugin via `$SHELL -c '<run>'`.\n\nDEPENDENCIES                                   *packer-plugin-dependencies*\nPlugins may specify dependencies via the `requires` key in their specification\ntable. This key can be a string or a list (table).\n\nIf `requires` is a string, it is treated as specifying a single plugin. If a\nplugin with the name given in `requires` is already known in the managed set,\nnothing happens. Otherwise, the string is treated as a plugin location string\nand the corresponding plugin is added to the managed set.\n\nIf `requires` is a list, it is treated as a list of plugin specifications\nfollowing the format given above.\n\nIf `ensure_dependencies` is true, the plugins specified in `requires` will be\ninstalled.\n\nPlugins specified in `requires` are removed when no active plugins require\nthem.\n\nLUAROCKS                                       *packer-plugin-luarocks*\n\nYou may specify that a plugin requires one or more Luarocks packages using the\n`rocks` key. This key takes either a string specifying the name of a package\n(e.g. `rocks=lpeg`), or a list specifying one or more packages. Entries in the\nlist may either be strings or lists --- the latter case is used to specify a\nparticular version of a package, e.g. `rocks = {'lpeg', {'lua-cjson',\n'2.1.0'}}`.\n\nCurrently, `packer` only supports equality constraints on package versions.\n\n`packer` also provides the function `packer.luarocks.install_commands()`, which\ncreates the `PackerRocks <cmd> <packages...>` command. `<cmd>` must be one of\n\"install\" or \"remove\"; `<packages...>` is one or more package names (currently,\nversion restrictions are not supported with this command). Running `PackerRocks`\nwill install or remove the given packages. You can use this command even if you\ndon't use `packer` to manage your plugins. However, please note that (1)\npackages installed through `PackerRocks` **will** be removed by calls to\n`packer.luarocks.clean()` (unless they are also part of a `packer` plugin\nspecification), and (2) you will need to manually invoke\n`packer.luarocks.setup_paths` (or otherwise modify your `package.path`) to\nensure that Neovim can find the installed packages.\n\nFinally, `packer` provides the function `packer.use_rocks`, which takes a string\nor table specifying one or more Luarocks packages as in the `rocks` key. You can\nuse this to ensure that `packer` downloads and manages some rocks which you want\nto use, but which are not associated with any particular plugin.\n\nSEQUENCING                                     *packer-plugin-sequencing*\n\nYou may specify a loading order for plugins using the `after` key. This key can\nbe a string or a list (table).\n\nIf `after` is a string, it must be the name of another plugin managed by\n`packer` (e.g. the final segment of a plugin's path - for a Github plugin\n`FooBar/Baz`, the name would be just `Baz`). If `after` is a table, it must be a\nlist of plugin names. If a plugin has an alias (i.e. uses the `as` key), this\nalias is its name.\n\nThe set of plugins specified in a plugin's `after` key must *all* be loaded\nbefore the plugin using `after` will be loaded. For example, in the\nspecification >lua\n  use {'FooBar/Baz', ft = 'bax'}\n  use {'Something/Else', after = 'Baz'}\n\nthe plugin `Else` will only be loaded after the plugin `Baz`, which itself is\nonly loaded for files with `bax` filetype.\n\nKEYBINDINGS                                    *packer-plugin-keybindings*\nPlugins may be lazy-loaded on the use of keybindings/maps. Individual\nkeybindings are specified under the `keys` key in a plugin specification\neither as a string (in which case they are treated as normal mode maps) or a\ntable in the format `{mode, map}`.\n\nLAZY-LOADING                                   *packer-lazy-load*\nTo optimize startup time, `packer.nvim` compiles code to perform the\nlazy-loading operations you specify. This means that you do not need to load\n`packer.nvim` unless you want to perform some plugin management operations.\n\nTo generate the compiled code, call `packer.compile(path)`, where `path` is\nsome file path on your `runtimepath`, with a `.vim` extension. This will\ngenerate a blend of Lua and Vimscript to load and configure all your\nlazy-loaded plugins (e.g. generating commands, autocommands, etc.) and save it\nto `path`. Then, when you start vim, the file at `path` is loaded (because\n`path` must be on your `runtimepath`), and lazy-loading works.\n\nIf `path` is not provided to |packer.compile()|, the output file will default\nto the value of `config.compile_path`.\n\nThe option `compile_on_sync`, which defaults to `true`, will run\n`packer.compile()` during `packer.sync()`, if set to `true`.\nNote that otherwise, you **must** run `packer.compile` yourself to generate\nthe lazy-loader file!\n\nUSING A FLOATING WINDOW                        *packer-floating-window*\nYou can configure Packer to use a floating window for command outputs by\npassing a utility function to `packer`'s config: >lua\n\n  packer.startup({function()\n    -- Your plugins here\n  end,\n  config = {\n    display = {\n      open_fn = require('packer.util').float,\n    }\n  }})\n<\nBy default, this floating window will show doubled borders. If you want to\ncustomize the window appearance, you can pass a configuration to `float`,\nwhich is the same configuration that would be passed to |nvim_open_win|: >lua\n\n  packer.startup({function()\n    -- Your plugins here\n  end,\n  config = {\n    display = {\n      open_fn = function()\n        return require('packer.util').float({ border = 'single' })\n      end\n    }\n  }})\n<\nPROFILING PLUGINS                              *packer-profiling*\nYou can measure how long it takes your plugins to load using packer's builtin\nprofiling functionality.\nIn order to use this functionality you must either enable profiling in your config, or pass in an argument\nwhen running packer compile.\n\nSetup via config >lua\n  config = {\n    profile = {\n      enable = true,\n      threshold = 1 -- the amount in ms that a plugin's load time must be over for it to be included in the profile\n    }\n  }\n<\n\nUsing the packer compile command\n>vim\n  :PackerCompile profile=true\n  \" or\n  :PackerCompile profile=false\n<\n\nNOTE you can also set a `threshold` in your profile config which is a number\nin `ms` above which plugin load times will be show e.g. if you set a threshold\nvalue of `3` then any plugin that loads slower than `3ms` will not be included in\nthe output window.\n\nThis will rebuild your `packer_compiled.vim` with profiling code included. In order to visualise the output of the profile\nRestart your neovim and run `PackerProfile`. This will open a window with the output of your profiling.\n\nEXTENDING PACKER                               *packer-extending*\nYou can add custom key handlers to `packer` by calling\n`packer.set_handler(name, func)` where `name` is the key you wish to handle\nand `func` is a function with the signature `func(plugins, plugin, value)`\nwhere `plugins` is the global table of managed plugins, `plugin` is the table\nfor a specific plugin, and `value` is the value associated with key `name` in\n`plugin`.\n\nRESULTS WINDOW KEYBINDINGS                     *packer-results-keybindings*\nOnce an operation completes, the results are shown in the display window.\n`packer` sets up default keybindings for this window:\n\nq                    close the display window\n<CR>                 toggle information about a particular plugin\nr                    revert an update\n\nThey can be configured by changing the value of `config.display.keybindings`\n(see |packer-configuration|). Setting it to `false` will disable all keybindings.\nSetting any of its keys to `false` will disable the corresponding keybinding.\n\nUSER AUTOCMDS                                  *packer-user-autocmds*\n`packer` runs most of its operations asyncronously. If you would like to\nimplement automations that require knowing when the operations are complete,\nyou can use the following User autocmds (see |User| for more info on how to\nuse):\n\n`PackerComplete`       Fires after install, update, clean, and sync\n                     asynchronous operations finish.\n`PackerCompileDone`    Fires after compiling (see |packer-lazy-load|)\n\n==============================================================================\nAPI                                            *packer-api*\n\nclean()\t\t                                     *packer.clean()*\n`clean` scans for and removes all disabled or no longer managed plugins. It is\ninvoked without arguments.\n\ncompile()\t\t                                   *packer.compile()*\n`compile` builds lazy-loader code from your plugin specification and saves it\nto either `config.compile_path` if it is invoked with no argument, or to the\npath it is invoked with if it is given a single argument. This path should end\nin `.vim` and be on your |runtimepath| in order for lazy-loading to work. You\n**must** call `compile` to update lazy-loaders after your configuration\nchanges.\n\ninit()\t\t                                     *packer.init()*\nInitializes `packer`; must be called before any calls to any other `packer`\nfunction. Takes an optional table of configuration values as described in\n|packer-configuration|.\n\ninstall()\t\t                                   *packer.install()*\n`install` installs any missing plugins, runs post-update hooks, and updates\nrplugins (|remote-plugin|) and helptags.\n\nIt can be invoked with no arguments or with a list of plugin names to install.\nThese plugin names must already be managed by `packer` via a call to\n|packer.use()|.\n\nreset()\t\t                                     *packer.reset()*\n`reset` empties the set of managed plugins. Called with no arguments; used to\nensure plugin specifications are reinitialized if the specification file is\nreloaded. Called by |packer.startup()| or manually before calling\n|packer.use()|.\n\nset_handler()\t\t                               *packer.set_handler()*\n`set_handler` allows custom extension of `packer`. See |packer-extending| for\ndetails.\n\nstartup()\t\t                                   *packer.startup()*\n`startup` is a convenience function for simple setup. See |packer-startup| for\ndetails.\n\nsync()\t\t                                     *packer.sync()*\n`sync` runs |packer.clean()| followed by |packer.update()|.\n\nSupports options as the first argument, see |packer.update()|.\n\nupdate()\t\t                                   *packer.update()*\n`update` installs any missing plugins, updates all installed plugins, runs\npost-update hooks, and updates rplugins (|remote-plugin|) and helptags.\n\nIt can be invoked with no arguments or with a list of plugin names to update.\nThese plugin names must already be managed by `packer` via a call to\n|packer.use()|.\n\nAdditionally, the first argument can be a table specifying options,\nsuch as `update({preview_updates = true}, ...)` to preview potential changes before updating\n(same as `PackerUpdate --preview`).\n\nsnapshot(snapshot_name, ...)\t\t                                *packer.snapshot()*\n`snapshot` takes the rev of all the installed plugins and serializes them into a Lua table which will be saved under `config.snapshot_path` (which is the directory that will hold all the snapshots files) as `config.snapshot_path/<snapshot_name>` or an absolute path provided by the users.\nOptionally plugins name can be specified so that only those plugins will be\nsnapshotted.\nSnapshot files can be loaded manually via `dofile` which will return a table with the plugins name as keys the commit short hash as value.\n\ndelete(snapshot_name)\t\t                                *packer.delete()*\n`delete` deletes a snapshot given the name or the absolute path.\n\nrollback(snapshot_name, ...)\t\t                                *packer.rollback()*\n`rollback` reverts all plugins or only the specified as extra arguments to the commit specified in the snapshot file\n\nuse()\t\t                                       *packer.use()*\n`use` allows you to add one or more plugins to the managed set. It can be\ninvoked as follows:\n- With a single plugin location string, e.g. `use <STRING>`\n- With a single plugin specification table, e.g. >lua\n  use {\n    'myusername/example',        -- The plugin location string\n    -- The following keys are all optional\n    disable = boolean,           -- Mark a plugin as inactive\n    as = string,                 -- Specifies an alias under which to install the plugin\n    installer = function,        -- Specifies custom installer. See |packer-custom-installers|\n    updater = function,          -- Specifies custom updater. See |packer-custom-installers|\n    after = string or list,      -- Specifies plugins to load before this plugin.\n    rtp = string,                -- Specifies a subdirectory of the plugin to add to runtimepath.\n    opt = boolean,               -- Manually marks a plugin as optional.\n    bufread = boolean,           -- Manually specifying if a plugin needs BufRead after being loaded\n    branch = string,             -- Specifies a git branch to use\n    tag = string,                -- Specifies a git tag to use. Supports '*' for \"latest tag\"\n    commit = string,             -- Specifies a git commit to use\n    lock = boolean,              -- Skip updating this plugin in updates/syncs. Still cleans.\n    run = string, function, or table  -- Post-update/install hook. See |packer-plugin-hooks|\n    requires = string or list    -- Specifies plugin dependencies. See |packer-plugin-dependencies|\n    config = string or function, -- Specifies code to run after this plugin is loaded.\n    rocks = string or list,      -- Specifies Luarocks dependencies for the plugin\n    -- The following keys all imply lazy-loading\n    cmd = string or list,        -- Specifies commands which load this plugin.  Can be an autocmd pattern.\n    ft = string or list,         -- Specifies filetypes which load this plugin.\n    keys = string or list,       -- Specifies maps which load this plugin. See |packer-plugin-keybindings|\n    event = string or list,      -- Specifies autocommand events which load this plugin.\n    fn = string or list          -- Specifies functions which load this plugin.\n    cond = string, function, or list of strings/functions,   -- Specifies a conditional test to load this plugin\n    setup = string or function,  -- Specifies code to run before this plugin is loaded. The code is ran even if\n                                 -- the plugin is waiting for other conditions (ft, cond...) to be met.\n    module = string or list      -- Specifies Lua module names for require. When requiring a string which starts\n                                 -- with one of these module names, the plugin will be loaded.\n    module_pattern = string/list -- Specifies Lua pattern of Lua module names for require. When requiring a string\n                                 -- which matches one of these patterns, the plugin will be loaded.\n  }\n- With a list of plugins specified in either of the above two forms\n\nFor the *cmd* option, the command may be a full command, or an autocommand pattern. If the command contains any\nnon-alphanumeric characters, it is assumed to be a pattern, and instead of creating a stub command, it creates\na CmdUndefined autocmd to load the plugin when a command that matches the pattern is invoked.\n\n vim:tw=78:ts=2:ft=help:norl:\n"
  },
  {
    "path": "lua/packer/async.lua",
    "content": "-- Adapted from https://ms-jpq.github.io/neovim-async-tutorial/\nlocal log = require 'packer.log'\nlocal yield = coroutine.yield\nlocal resume = coroutine.resume\nlocal thread_create = coroutine.create\n\nlocal function EMPTY_CALLBACK() end\nlocal function step(func, callback)\n  local thread = thread_create(func)\n  local tick = nil\n  tick = function(...)\n    local ok, val = resume(thread, ...)\n    if ok then\n      if type(val) == 'function' then\n        val(tick)\n      else\n        (callback or EMPTY_CALLBACK)(val)\n      end\n    else\n      log.error('Error in coroutine: ' .. val);\n      (callback or EMPTY_CALLBACK)(nil)\n    end\n  end\n\n  tick()\nend\n\nlocal function wrap(func)\n  return function(...)\n    local params = { ... }\n    return function(tick)\n      params[#params + 1] = tick\n      return func(unpack(params))\n    end\n  end\nend\n\nlocal function join(...)\n  local thunks = { ... }\n  local thunk_all = function(s)\n    if #thunks == 0 then\n      return s()\n    end\n    local to_go = #thunks\n    local results = {}\n    for i, thunk in ipairs(thunks) do\n      local callback = function(...)\n        results[i] = { ... }\n        if to_go == 1 then\n          s(unpack(results))\n        else\n          to_go = to_go - 1\n        end\n      end\n\n      thunk(callback)\n    end\n  end\n\n  return thunk_all\nend\n\nlocal function wait_all(...)\n  return yield(join(...))\nend\n\nlocal function pool(n, interrupt_check, ...)\n  local thunks = { ... }\n  return function(s)\n    if #thunks == 0 then\n      return s()\n    end\n    local remaining = { select(n + 1, unpack(thunks)) }\n    local results = {}\n    local to_go = #thunks\n    local make_callback = nil\n    make_callback = function(idx, left)\n      local i = (left == nil) and idx or (idx + left)\n      return function(...)\n        results[i] = { ... }\n        to_go = to_go - 1\n        if to_go == 0 then\n          s(unpack(results))\n        elseif not interrupt_check or not interrupt_check() then\n          if remaining and #remaining > 0 then\n            local next_task = table.remove(remaining)\n            next_task(make_callback(n, #remaining + 1))\n          end\n        end\n      end\n    end\n\n    for i = 1, math.min(n, #thunks) do\n      local thunk = thunks[i]\n      thunk(make_callback(i))\n    end\n  end\nend\n\nlocal function wait_pool(limit, ...)\n  return yield(pool(limit, false, ...))\nend\n\nlocal function interruptible_wait_pool(limit, interrupt_check, ...)\n  return yield(pool(limit, interrupt_check, ...))\nend\n\nlocal function main(f)\n  vim.schedule(f)\nend\n\nlocal M = {\n  --- Wrapper for functions that do not take a callback to make async functions\n  sync = wrap(step),\n  --- Alias for yielding to await the result of an async function\n  wait = yield,\n  --- Await the completion of a full set of async functions\n  wait_all = wait_all,\n  --- Await the completion of a full set of async functions, with a limit on how many functions can\n  --  run simultaneously\n  wait_pool = wait_pool,\n  --- Like wait_pool, but additionally checks at every function completion to see if a condition is\n  --  met indicating that it should keep running the remaining tasks\n  interruptible_wait_pool = interruptible_wait_pool,\n  --- Wrapper for functions that do take a callback to make async functions\n  wrap = wrap,\n  --- Convenience function to ensure a function runs on the main \"thread\" (i.e. for functions which\n  --  use Neovim functions, etc.)\n  main = main,\n}\n\nreturn M\n"
  },
  {
    "path": "lua/packer/clean.lua",
    "content": "local plugin_utils = require 'packer.plugin_utils'\nlocal a = require 'packer.async'\nlocal display = require 'packer.display'\nlocal log = require 'packer.log'\nlocal util = require 'packer.util'\n\nlocal await = a.wait\nlocal async = a.sync\n\nlocal config\n\nlocal PLUGIN_OPTIONAL_LIST = 1\nlocal PLUGIN_START_LIST = 2\n\nlocal function is_dirty(plugin, typ)\n  return (plugin.opt and typ == PLUGIN_START_LIST) or (not plugin.opt and typ == PLUGIN_OPTIONAL_LIST)\nend\n\n-- Find and remove any plugins not currently configured for use\nlocal clean_plugins = function(_, plugins, fs_state, results)\n  return async(function()\n    log.debug 'Starting clean'\n    local dirty_plugins = {}\n    results = results or {}\n    results.removals = results.removals or {}\n    local opt_plugins = vim.deepcopy(fs_state.opt)\n    local start_plugins = vim.deepcopy(fs_state.start)\n    local missing_plugins = fs_state.missing\n    -- test for dirty / 'missing' plugins\n    for _, plugin_config in pairs(plugins) do\n      local path = plugin_config.install_path\n      local plugin_source = nil\n      if opt_plugins[path] then\n        plugin_source = PLUGIN_OPTIONAL_LIST\n        opt_plugins[path] = nil\n      elseif start_plugins[path] then\n        plugin_source = PLUGIN_START_LIST\n        start_plugins[path] = nil\n      end\n\n      -- We don't want to report paths which don't exist for removal; that will confuse people\n      local path_exists = false\n      if missing_plugins[plugin_config.short_name] or plugin_config.disable then\n        path_exists = vim.loop.fs_stat(path) ~= nil\n      end\n\n      local plugin_missing = path_exists and missing_plugins[plugin_config.short_name]\n      local disabled_but_installed = path_exists and plugin_config.disable\n      if plugin_missing or is_dirty(plugin_config, plugin_source) or disabled_but_installed then\n        dirty_plugins[#dirty_plugins + 1] = path\n      end\n    end\n\n    -- Any path which was not set to `nil` above will be set to dirty here\n    local function mark_remaining_as_dirty(plugin_list)\n      for path, _ in pairs(plugin_list) do\n        dirty_plugins[#dirty_plugins + 1] = path\n      end\n    end\n\n    mark_remaining_as_dirty(opt_plugins)\n    mark_remaining_as_dirty(start_plugins)\n    if next(dirty_plugins) then\n      local lines = {}\n      for _, path in ipairs(dirty_plugins) do\n        table.insert(lines, '  - ' .. path)\n      end\n      await(a.main)\n      if config.autoremove or await(display.ask_user('Removing the following directories. OK? (y/N)', lines)) then\n        results.removals = dirty_plugins\n        log.debug('Removed ' .. vim.inspect(dirty_plugins))\n        for _, path in ipairs(dirty_plugins) do\n          local result = vim.fn.delete(path, 'rf')\n          if result == -1 then\n            log.warn('Could not remove ' .. path)\n          end\n        end\n      else\n        log.warn 'Cleaning cancelled!'\n      end\n    else\n      log.info 'Already clean!'\n    end\n  end)\nend\n\nlocal function cfg(_config)\n  config = _config\nend\n\nlocal clean = setmetatable({ cfg = cfg }, { __call = clean_plugins })\nreturn clean\n"
  },
  {
    "path": "lua/packer/compile.lua",
    "content": "-- Compiling plugin specifications to Lua for lazy-loading\nlocal util = require 'packer.util'\nlocal log = require 'packer.log'\nlocal fmt = string.format\nlocal luarocks = require 'packer.luarocks'\n\nlocal config\nlocal function cfg(_config)\n  config = _config.profile\nend\n\nlocal feature_guard = [[\nif !has('nvim-0.5')\n  echohl WarningMsg\n  echom \"Invalid Neovim version for packer.nvim!\"\n  echohl None\n  finish\nendif\n\npackadd packer.nvim\n\ntry\n]]\n\nlocal feature_guard_lua = [[\nif vim.api.nvim_call_function('has', {'nvim-0.5'}) ~= 1 then\n  vim.api.nvim_command('echohl WarningMsg | echom \"Invalid Neovim version for packer.nvim! | echohl None\"')\n  return\nend\n\nvim.api.nvim_command('packadd packer.nvim')\n\nlocal no_errors, error_msg = pcall(function()\n]]\n\nlocal enter_packer_compile = [[\n_G._packer = _G._packer or {}\n_G._packer.inside_compile = true\n]]\n\nlocal exit_packer_compile = [[\n\n_G._packer.inside_compile = false\nif _G._packer.needs_bufread == true then\n  vim.cmd(\"doautocmd BufRead\")\nend\n_G._packer.needs_bufread = false\n]]\n\nlocal catch_errors = [[\ncatch\n  echohl ErrorMsg\n  echom \"Error in packer_compiled: \" .. v:exception\n  echom \"Please check your config for correctness\"\n  echohl None\nendtry\n]]\n\nlocal catch_errors_lua = [[\nend)\n\nif not no_errors then\n  error_msg = error_msg:gsub('\"', '\\\\\"')\n  vim.api.nvim_command('echohl ErrorMsg | echom \"Error in packer_compiled: '..error_msg..'\" | echom \"Please check your config for correctness\" | echohl None')\nend\n]]\n\n---@param should_profile boolean\n---@return string\nlocal profile_time = function(should_profile)\n  return fmt(\n    [[\nlocal time\nlocal profile_info\nlocal should_profile = %s\nif should_profile then\n  local hrtime = vim.loop.hrtime\n  profile_info = {}\n  time = function(chunk, start)\n    if start then\n      profile_info[chunk] = hrtime()\n    else\n      profile_info[chunk] = (hrtime() - profile_info[chunk]) / 1e6\n    end\n  end\nelse\n  time = function(chunk, start) end\nend\n]],\n    vim.inspect(should_profile)\n  )\nend\n\nlocal profile_output = [[\nlocal function save_profiles(threshold)\n  local sorted_times = {}\n  for chunk_name, time_taken in pairs(profile_info) do\n    sorted_times[#sorted_times + 1] = {chunk_name, time_taken}\n  end\n  table.sort(sorted_times, function(a, b) return a[2] > b[2] end)\n  local results = {}\n  for i, elem in ipairs(sorted_times) do\n    if not threshold or threshold and elem[2] > threshold then\n      results[i] = elem[1] .. ' took ' .. elem[2] .. 'ms'\n    end\n  end\n  if threshold then\n    table.insert(results, '(Only showing plugins that took longer than ' .. threshold .. ' ms ' .. 'to load)')\n  end\n\n  _G._packer.profile_output = results\nend\n]]\n\n---@param threshold number\n---@return string\nlocal conditionally_output_profile = function(threshold)\n  if threshold then\n    return fmt(\n      [[\nif should_profile then save_profiles(%d) end\n]],\n      threshold\n    )\n  else\n    return [[\nif should_profile then save_profiles() end\n]]\n  end\nend\n\nlocal try_loadstring = [[\nlocal function try_loadstring(s, component, name)\n  local success, result = pcall(loadstring(s), name, _G.packer_plugins[name])\n  if not success then\n    vim.schedule(function()\n      vim.api.nvim_notify('packer.nvim: Error running ' .. component .. ' for ' .. name .. ': ' .. result, vim.log.levels.ERROR, {})\n    end)\n  end\n  return result\nend\n]]\n\nlocal module_loader = [[\nlocal lazy_load_called = {['packer.load'] = true}\nlocal function lazy_load_module(module_name)\n  local to_load = {}\n  if lazy_load_called[module_name] then return nil end\n  lazy_load_called[module_name] = true\n  for module_pat, plugin_name in pairs(module_lazy_loads) do\n    if not _G.packer_plugins[plugin_name].loaded and string.match(module_name, module_pat) then\n      to_load[#to_load + 1] = plugin_name\n    end\n  end\n\n  if #to_load > 0 then\n    require('packer.load')(to_load, {module = module_name}, _G.packer_plugins)\n    local loaded_mod = package.loaded[module_name]\n    if loaded_mod then\n      return function(modname) return loaded_mod end\n    end\n  end\nend\n\nif not vim.g.packer_custom_loader_enabled then\n  table.insert(package.loaders, 1, lazy_load_module)\n  vim.g.packer_custom_loader_enabled = true\nend\n]]\n\nlocal function timed_chunk(chunk, name, output_table)\n  output_table = output_table or {}\n  output_table[#output_table + 1] = 'time([[' .. name .. ']], true)'\n  if type(chunk) == 'string' then\n    output_table[#output_table + 1] = chunk\n  else\n    vim.list_extend(output_table, chunk)\n  end\n\n  output_table[#output_table + 1] = 'time([[' .. name .. ']], false)'\n  return output_table\nend\n\nlocal function dump_loaders(loaders)\n  local result = vim.deepcopy(loaders)\n  for k, _ in pairs(result) do\n    if result[k].only_setup or result[k].only_sequence then\n      result[k].loaded = true\n    end\n    result[k].only_setup = nil\n    result[k].only_sequence = nil\n  end\n\n  return vim.inspect(result)\nend\n\nlocal function make_try_loadstring(item, chunk, name)\n  local bytecode = string.dump(item, true)\n  local executable_string = 'try_loadstring(' .. vim.inspect(bytecode) .. ', \"' .. chunk .. '\", \"' .. name .. '\")'\n  return executable_string, bytecode\nend\n\nlocal after_plugin_pattern = table.concat({ 'after', 'plugin', [[**/*.\\(vim\\|lua\\)]] }, util.get_separator())\nlocal function detect_after_plugin(name, plugin_path)\n  local path = plugin_path .. util.get_separator() .. after_plugin_pattern\n  local glob_ok, files = pcall(vim.fn.glob, path, false, true)\n  if not glob_ok then\n    if string.find(files, 'E77') then\n      return { path }\n    else\n      log.error('Error compiling ' .. name .. ': ' .. vim.inspect(files))\n      error(files)\n    end\n  elseif #files > 0 then\n    return files\n  end\n\n  return nil\nend\n\nlocal ftdetect_patterns = {\n  table.concat({ 'ftdetect', [[**/*.\\(vim\\|lua\\)]] }, util.get_separator()),\n  table.concat({ 'after', 'ftdetect', [[**/*.\\(vim\\|lua\\)]] }, util.get_separator()),\n}\nlocal function detect_ftdetect(name, plugin_path)\n  local paths = {\n    plugin_path .. util.get_separator() .. ftdetect_patterns[1],\n    plugin_path .. util.get_separator() .. ftdetect_patterns[2],\n  }\n  local source_paths = {}\n  for i = 1, 2 do\n    local path = paths[i]\n    local glob_ok, files = pcall(vim.fn.glob, path, false, true)\n    if not glob_ok then\n      if string.find(files, 'E77') then\n        source_paths[#source_paths + 1] = path\n      else\n        log.error('Error compiling ' .. name .. ': ' .. vim.inspect(files))\n        error(files)\n      end\n    elseif #files > 0 then\n      vim.list_extend(source_paths, files)\n    end\n  end\n\n  return source_paths\nend\n\nlocal source_dirs = { 'ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin' }\nlocal function detect_bufread(plugin_path)\n  local path = plugin_path\n  for i = 1, 4 do\n    if #vim.fn.finddir(source_dirs[i], path) > 0 then\n      return true\n    end\n  end\n  return false\nend\n\nlocal function make_loaders(_, plugins, output_lua, should_profile)\n  local loaders = {}\n  local configs = {}\n  local rtps = {}\n  local setup = {}\n  local fts = {}\n  local events = {}\n  local condition_ids = {}\n  local commands = {}\n  local keymaps = {}\n  local after = {}\n  local fns = {}\n  local ftdetect_paths = {}\n  local module_lazy_loads = {}\n  for name, plugin in pairs(plugins) do\n    if not plugin.disable then\n      plugin.simple_load = true\n      local quote_name = \"'\" .. name .. \"'\"\n      if plugin.config and not plugin.executable_config then\n        plugin.simple_load = false\n        plugin.executable_config = {}\n        if type(plugin.config) ~= 'table' then\n          plugin.config = { plugin.config }\n        end\n        for i, config_item in ipairs(plugin.config) do\n          local executable_string = config_item\n          if type(config_item) == 'function' then\n            local bytecode\n            executable_string, bytecode = make_try_loadstring(config_item, 'config', name)\n            plugin.config[i] = bytecode\n          end\n\n          table.insert(plugin.executable_config, executable_string)\n        end\n      end\n\n      local path = plugin.install_path\n      if plugin.rtp then\n        path = util.join_paths(plugin.install_path, plugin.rtp)\n        table.insert(rtps, path)\n      end\n\n      loaders[name] = {\n        loaded = not plugin.opt,\n        config = plugin.config,\n        path = path,\n        only_sequence = plugin.manual_opt == nil,\n        only_setup = false,\n      }\n\n      if plugin.opt then\n        plugin.simple_load = false\n        loaders[name].after_files = detect_after_plugin(name, loaders[name].path)\n        if plugin.bufread ~= nil then\n          loaders[name].needs_bufread = plugin.bufread\n        else\n          loaders[name].needs_bufread = detect_bufread(loaders[name].path)\n        end\n      end\n\n      if plugin.setup then\n        plugin.simple_load = false\n        if type(plugin.setup) ~= 'table' then\n          plugin.setup = { plugin.setup }\n        end\n        for i, setup_item in ipairs(plugin.setup) do\n          if type(setup_item) == 'function' then\n            plugin.setup[i], _ = make_try_loadstring(setup_item, 'setup', name)\n          end\n        end\n\n        loaders[name].only_setup = plugin.manual_opt == nil\n        setup[name] = plugin.setup\n      end\n\n      -- Keep this as first opt loader to maintain only_cond ?\n      if plugin.cond ~= nil then\n        plugin.simple_load = false\n        loaders[name].only_sequence = false\n        loaders[name].only_setup = false\n        loaders[name].only_cond = true\n        if type(plugin.cond) ~= 'table' then\n          plugin.cond = { plugin.cond }\n        end\n\n        for _, condition in ipairs(plugin.cond) do\n          loaders[name].cond = {}\n          if type(condition) == 'function' then\n            _, condition = make_try_loadstring(condition, 'condition', name)\n          elseif type(condition) == 'string' then\n            condition = 'return ' .. condition\n          end\n\n          condition_ids[condition] = condition_ids[condition] or {}\n          table.insert(loaders[name].cond, condition)\n          table.insert(condition_ids[condition], name)\n        end\n      end\n\n      -- Add the git URL for displaying in PackerStatus and PackerSync. https://github.com/wbthomason/packer.nvim/issues/542\n      loaders[name].url = plugin.url\n\n      if plugin.ft then\n        plugin.simple_load = false\n        loaders[name].only_sequence = false\n        loaders[name].only_setup = false\n        loaders[name].only_cond = false\n        vim.list_extend(ftdetect_paths, detect_ftdetect(name, loaders[name].path))\n        if type(plugin.ft) == 'string' then\n          plugin.ft = { plugin.ft }\n        end\n        for _, ft in ipairs(plugin.ft) do\n          fts[ft] = fts[ft] or {}\n          table.insert(fts[ft], quote_name)\n        end\n      end\n\n      if plugin.event then\n        plugin.simple_load = false\n        loaders[name].only_sequence = false\n        loaders[name].only_setup = false\n        loaders[name].only_cond = false\n        if type(plugin.event) == 'string' then\n          if not plugin.event:find '%s' then\n            plugin.event = { plugin.event .. ' *' }\n          else\n            plugin.event = { plugin.event }\n          end\n        end\n\n        for _, event in ipairs(plugin.event) do\n          if event:sub(#event, -1) ~= '*' and not event:find '%s' then\n            event = event .. ' *'\n          end\n          events[event] = events[event] or {}\n          table.insert(events[event], quote_name)\n        end\n      end\n\n      if plugin.cmd then\n        plugin.simple_load = false\n        loaders[name].only_sequence = false\n        loaders[name].only_setup = false\n        loaders[name].only_cond = false\n        if type(plugin.cmd) == 'string' then\n          plugin.cmd = { plugin.cmd }\n        end\n\n        loaders[name].commands = {}\n        for _, command in ipairs(plugin.cmd) do\n          commands[command] = commands[command] or {}\n          table.insert(loaders[name].commands, command)\n          table.insert(commands[command], quote_name)\n        end\n      end\n\n      if plugin.keys then\n        plugin.simple_load = false\n        loaders[name].only_sequence = false\n        loaders[name].only_setup = false\n        loaders[name].only_cond = false\n        if type(plugin.keys) == 'string' then\n          plugin.keys = { plugin.keys }\n        end\n        loaders[name].keys = {}\n        for _, keymap in ipairs(plugin.keys) do\n          if type(keymap) == 'string' then\n            keymap = { '', keymap }\n          end\n          keymaps[keymap] = keymaps[keymap] or {}\n          table.insert(loaders[name].keys, keymap)\n          table.insert(keymaps[keymap], quote_name)\n        end\n      end\n\n      if plugin.after then\n        plugin.simple_load = false\n        loaders[name].only_setup = false\n\n        if type(plugin.after) == 'string' then\n          plugin.after = { plugin.after }\n        end\n\n        for _, other_plugin in ipairs(plugin.after) do\n          after[other_plugin] = after[other_plugin] or {}\n          table.insert(after[other_plugin], name)\n        end\n      end\n\n      if plugin.wants then\n        plugin.simple_load = false\n        if type(plugin.wants) == 'string' then\n          plugin.wants = { plugin.wants }\n        end\n        loaders[name].wants = plugin.wants\n      end\n\n      if plugin.fn then\n        plugin.simple_load = false\n        loaders[name].only_sequence = false\n        loaders[name].only_setup = false\n        if type(plugin.fn) == 'string' then\n          plugin.fn = { plugin.fn }\n        end\n        for _, fn in ipairs(plugin.fn) do\n          fns[fn] = fns[fn] or {}\n          table.insert(fns[fn], quote_name)\n        end\n      end\n\n      if plugin.module or plugin.module_pattern then\n        plugin.simple_load = false\n        loaders[name].only_sequence = false\n        loaders[name].only_setup = false\n        loaders[name].only_cond = false\n\n        if plugin.module then\n          if type(plugin.module) == 'string' then\n            plugin.module = { plugin.module }\n          end\n\n          for _, module_name in ipairs(plugin.module) do\n            module_lazy_loads['^' .. vim.pesc(module_name)] = name\n          end\n        else\n          if type(plugin.module_pattern) == 'string' then\n            plugin.module_pattern = { plugin.module_pattern }\n          end\n\n          for _, module_pattern in ipairs(plugin.module_pattern) do\n            module_lazy_loads[module_pattern] = name\n          end\n        end\n      end\n\n      if plugin.config and (not plugin.opt or loaders[name].only_setup) then\n        plugin.simple_load = false\n        plugin.only_config = true\n        configs[name] = plugin.executable_config\n      end\n    end\n  end\n\n  local ft_aucmds = {}\n  for ft, names in pairs(fts) do\n    table.insert(\n      ft_aucmds,\n      fmt(\n        'vim.cmd [[au FileType %s ++once lua require(\"packer.load\")({%s}, { ft = \"%s\" }, _G.packer_plugins)]]',\n        ft,\n        table.concat(names, ', '),\n        ft\n      )\n    )\n  end\n\n  local event_aucmds = {}\n  for event, names in pairs(events) do\n    table.insert(\n      event_aucmds,\n      fmt(\n        'vim.cmd [[au %s ++once lua require(\"packer.load\")({%s}, { event = \"%s\" }, _G.packer_plugins)]]',\n        event,\n        table.concat(names, ', '),\n        event:gsub([[\\]], [[\\\\]])\n      )\n    )\n  end\n\n  local config_lines = {}\n  for name, plugin_config in pairs(configs) do\n    local lines = { '-- Config for: ' .. name }\n    timed_chunk(plugin_config, 'Config for ' .. name, lines)\n    vim.list_extend(config_lines, lines)\n  end\n\n  local rtp_line = ''\n  for _, rtp in ipairs(rtps) do\n    rtp_line = rtp_line .. ' .. \",' .. vim.fn.escape(rtp, '\\\\,') .. '\"'\n  end\n\n  if rtp_line ~= '' then\n    rtp_line = 'vim.o.runtimepath = vim.o.runtimepath' .. rtp_line\n  end\n\n  local setup_lines = {}\n  for name, plugin_setup in pairs(setup) do\n    local lines = { '-- Setup for: ' .. name }\n    timed_chunk(plugin_setup, 'Setup for ' .. name, lines)\n    if loaders[name].only_setup then\n      timed_chunk('vim.cmd [[packadd ' .. name .. ']]', 'packadd for ' .. name, lines)\n    end\n\n    vim.list_extend(setup_lines, lines)\n  end\n\n  local conditionals = {}\n  for _, names in pairs(condition_ids) do\n    for _, name in ipairs(names) do\n      if loaders[name].only_cond then\n        timed_chunk(\n          fmt('  require(\"packer.load\")({\"%s\"}, {}, _G.packer_plugins)', name),\n          'Conditional loading of ' .. name,\n          conditionals\n        )\n      end\n    end\n  end\n\n  local command_defs = {}\n  for command, names in pairs(commands) do\n    local command_line\n    if string.match(command, '^%w+$') then\n      -- Better command completions here are due to @folke and @lewis6991\n      command_line = fmt(\n        [[pcall(vim.api.nvim_create_user_command, '%s', function(cmdargs)\n          require('packer.load')({%s}, { cmd = '%s', l1 = cmdargs.line1, l2 = cmdargs.line2, bang = cmdargs.bang, args = cmdargs.args, mods = cmdargs.mods }, _G.packer_plugins)\n        end,\n        {nargs = '*', range = true, bang = true, complete = function()\n          require('packer.load')({%s}, {}, _G.packer_plugins)\n          return vim.fn.getcompletion('%s ', 'cmdline')\n      end})]],\n        command,\n        table.concat(names, ', '),\n        command,\n        table.concat(names, ', '),\n        command,\n        command\n      )\n    else\n      command_line = fmt(\n        'pcall(vim.cmd, [[au CmdUndefined %s ++once lua require\"packer.load\"({%s}, {}, _G.packer_plugins)]])',\n        command,\n        table.concat(names, ', ')\n      )\n    end\n    command_defs[#command_defs + 1] = command_line\n  end\n\n  local keymap_defs = {}\n  for keymap, names in pairs(keymaps) do\n    local prefix = nil\n    if keymap[1] ~= 'i' then\n      prefix = ''\n    end\n    local escaped_map_lt = string.gsub(keymap[2], '<', '<lt>')\n    local escaped_map = string.gsub(escaped_map_lt, '([\\\\\"])', '\\\\%1')\n    local keymap_line = fmt(\n      'vim.cmd [[%snoremap <silent> %s <cmd>lua require(\"packer.load\")({%s}, { keys = \"%s\"%s }, _G.packer_plugins)<cr>]]',\n      keymap[1],\n      keymap[2],\n      table.concat(names, ', '),\n      escaped_map,\n      prefix == nil and '' or (', prefix = \"' .. prefix .. '\"')\n    )\n\n    table.insert(keymap_defs, keymap_line)\n  end\n\n  local sequence_loads = {}\n  for pre, posts in pairs(after) do\n    if plugins[pre] == nil then\n      error(string.format('Dependency %s for %s not found', pre, vim.inspect(posts)))\n    end\n\n    if plugins[pre].opt then\n      loaders[pre].after = posts\n    elseif plugins[pre].only_config then\n      loaders[pre].after = posts\n      loaders[pre].only_sequence = true\n      loaders[pre].only_config = true\n    end\n\n    if plugins[pre].simple_load or plugins[pre].opt or plugins[pre].only_config then\n      for _, name in ipairs(posts) do\n        loaders[name].load_after = {}\n        sequence_loads[name] = sequence_loads[name] or {}\n        table.insert(sequence_loads[name], pre)\n      end\n    end\n  end\n\n  local fn_aucmds = {}\n  for fn, names in pairs(fns) do\n    table.insert(\n      fn_aucmds,\n      fmt(\n        'vim.cmd[[au FuncUndefined %s ++once lua require(\"packer.load\")({%s}, {}, _G.packer_plugins)]]',\n        fn,\n        table.concat(names, ', ')\n      )\n    )\n  end\n\n  local sequence_lines = {}\n  local graph = {}\n  for name, precedents in pairs(sequence_loads) do\n    graph[name] = graph[name] or { in_links = {}, out_links = {} }\n    for _, pre in ipairs(precedents) do\n      graph[pre] = graph[pre] or { in_links = {}, out_links = {} }\n      graph[name].in_links[pre] = true\n      table.insert(graph[pre].out_links, name)\n    end\n  end\n\n  local frontier = {}\n  for name, links in pairs(graph) do\n    if next(links.in_links) == nil then\n      table.insert(frontier, name)\n    end\n  end\n\n  while next(frontier) ~= nil do\n    local plugin = table.remove(frontier)\n    if loaders[plugin].only_sequence and not (loaders[plugin].only_setup or loaders[plugin].only_config) then\n      table.insert(sequence_lines, 'vim.cmd [[ packadd ' .. plugin .. ' ]]')\n      if plugins[plugin].config then\n        local lines = { '', '-- Config for: ' .. plugin }\n        vim.list_extend(lines, plugins[plugin].executable_config)\n        table.insert(lines, '')\n        vim.list_extend(sequence_lines, lines)\n      end\n    end\n\n    for _, name in ipairs(graph[plugin].out_links) do\n      if not loaders[plugin].only_sequence then\n        loaders[name].only_sequence = false\n        loaders[name].load_after[plugin] = true\n      end\n\n      graph[name].in_links[plugin] = nil\n      if next(graph[name].in_links) == nil then\n        table.insert(frontier, name)\n      end\n    end\n\n    graph[plugin] = nil\n  end\n\n  if next(graph) then\n    log.warn 'Cycle detected in sequenced loads! Load order may be incorrect'\n    -- TODO: This should actually just output the cycle, then continue with toposort. But I'm too\n    -- lazy to do that right now, so.\n    for plugin, _ in pairs(graph) do\n      table.insert(sequence_lines, 'vim.cmd [[ packadd ' .. plugin .. ' ]]')\n      if plugins[plugin].config then\n        local lines = { '-- Config for: ' .. plugin }\n        vim.list_extend(lines, plugins[plugin].config)\n        vim.list_extend(sequence_lines, lines)\n      end\n    end\n  end\n\n  -- Output everything:\n\n  -- First, the Lua code\n  local result = { (output_lua and '--' or '\"') .. ' Automatically generated packer.nvim plugin loader code\\n' }\n  if output_lua then\n    table.insert(result, feature_guard_lua)\n  else\n    table.insert(result, feature_guard)\n    table.insert(result, 'lua << END')\n  end\n  table.insert(result, enter_packer_compile)\n  table.insert(result, profile_time(should_profile))\n  table.insert(result, profile_output)\n  timed_chunk(luarocks.generate_path_setup(), 'Luarocks path setup', result)\n  timed_chunk(try_loadstring, 'try_loadstring definition', result)\n  timed_chunk(fmt('_G.packer_plugins = %s\\n', dump_loaders(loaders)), 'Defining packer_plugins', result)\n  -- Then the runtimepath line\n  if rtp_line ~= '' then\n    table.insert(result, '-- Runtimepath customization')\n    timed_chunk(rtp_line, 'Runtimepath customization', result)\n  end\n\n  -- Then the module lazy loads\n  if next(module_lazy_loads) then\n    table.insert(result, 'local module_lazy_loads = ' .. vim.inspect(module_lazy_loads))\n    table.insert(result, module_loader)\n  end\n\n  -- Then setups, configs, and conditionals\n  if next(setup_lines) then\n    vim.list_extend(result, setup_lines)\n  end\n  if next(config_lines) then\n    vim.list_extend(result, config_lines)\n  end\n  if next(conditionals) then\n    table.insert(result, '-- Conditional loads')\n    vim.list_extend(result, conditionals)\n  end\n\n  -- The sequenced loads\n  if next(sequence_lines) then\n    table.insert(result, '-- Load plugins in order defined by `after`')\n    timed_chunk(sequence_lines, 'Sequenced loading', result)\n  end\n\n  -- The command and keymap definitions\n  if next(command_defs) then\n    table.insert(result, '\\n-- Command lazy-loads')\n    timed_chunk(command_defs, 'Defining lazy-load commands', result)\n    table.insert(result, '')\n  end\n\n  if next(keymap_defs) then\n    table.insert(result, '-- Keymap lazy-loads')\n    timed_chunk(keymap_defs, 'Defining lazy-load keymaps', result)\n    table.insert(result, '')\n  end\n\n  -- The filetype, event and function autocommands\n  local some_ft = next(ft_aucmds) ~= nil\n  local some_event = next(event_aucmds) ~= nil\n  local some_fn = next(fn_aucmds) ~= nil\n  if some_ft or some_event or some_fn then\n    table.insert(result, 'vim.cmd [[augroup packer_load_aucmds]]\\nvim.cmd [[au!]]')\n  end\n\n  if some_ft then\n    table.insert(result, '  -- Filetype lazy-loads')\n    timed_chunk(ft_aucmds, 'Defining lazy-load filetype autocommands', result)\n  end\n\n  if some_event then\n    table.insert(result, '  -- Event lazy-loads')\n    timed_chunk(event_aucmds, 'Defining lazy-load event autocommands', result)\n  end\n\n  if some_fn then\n    table.insert(result, '  -- Function lazy-loads')\n    timed_chunk(fn_aucmds, 'Defining lazy-load function autocommands', result)\n  end\n\n  if some_ft or some_event or some_fn then\n    table.insert(result, 'vim.cmd(\"augroup END\")')\n  end\n  if next(ftdetect_paths) then\n    table.insert(result, 'vim.cmd [[augroup filetypedetect]]')\n    for _, path in ipairs(ftdetect_paths) do\n      local escaped_path = vim.fn.escape(path, ' ')\n      timed_chunk('vim.cmd [[source ' .. escaped_path .. ']]', 'Sourcing ftdetect script at: ' .. escaped_path, result)\n    end\n\n    table.insert(result, 'vim.cmd(\"augroup END\")')\n  end\n\n  table.insert(result, exit_packer_compile)\n\n  table.insert(result, conditionally_output_profile(config.threshold))\n  if output_lua then\n    table.insert(result, catch_errors_lua)\n  else\n    table.insert(result, 'END\\n')\n    table.insert(result, catch_errors)\n  end\n  return table.concat(result, '\\n')\nend\n\nlocal compile = setmetatable({ cfg = cfg }, { __call = make_loaders })\n\ncompile.opt_keys = { 'after', 'cmd', 'ft', 'keys', 'event', 'cond', 'setup', 'fn', 'module', 'module_pattern' }\n\nreturn compile\n"
  },
  {
    "path": "lua/packer/display.lua",
    "content": "local api = vim.api\nlocal log = require 'packer.log'\nlocal a = require 'packer.async'\nlocal plugin_utils = require 'packer.plugin_utils'\nlocal fmt = string.format\n\nlocal function interactive(config)\n  return not config.non_interactive and #api.nvim_list_uis() > 0\nend\n\n-- Temporary wrappers to compensate for the updated extmark API, until most people have updated to\n-- the latest HEAD (2020-09-04)\nlocal function set_extmark(buf, ns, id, line, col)\n  if not api.nvim_buf_is_valid(buf) then\n    return\n  end\n  local opts = { id = id }\n  local result, mark_id = pcall(api.nvim_buf_set_extmark, buf, ns, line, col, opts)\n  if result then\n    return mark_id\n  end\n  -- We must be in an older version of Neovim\n  if not id then\n    id = 0\n  end\n  return api.nvim_buf_set_extmark(buf, ns, id, line, col, {})\nend\n\nlocal function get_extmark_by_id(buf, ns, id)\n  local result, line, col = pcall(api.nvim_buf_get_extmark_by_id, buf, ns, id, {})\n  if result then\n    return line, col\n  else\n    log.error('Failed to get extmark: ' .. line)\n  end\n  -- We must be in an older version of Neovim\n  return api.nvim_buf_get_extmark_by_id(buf, ns, id)\nend\n\nlocal function strip_newlines(raw_lines)\n  local lines = {}\n  for _, line in ipairs(raw_lines) do\n    for _, chunk in ipairs(vim.split(line, '\\n')) do\n      table.insert(lines, chunk)\n    end\n  end\n\n  return lines\nend\n\nlocal function unpack_config_value(value, value_type, formatter)\n  if value_type == 'string' then\n    return { value }\n  elseif value_type == 'table' then\n    local result = {}\n    for _, k in ipairs(value) do\n      local item = formatter and formatter(k) or k\n      table.insert(result, fmt('  - %s', item))\n    end\n    return result\n  end\n  return ''\nend\n\nlocal function format_keys(value)\n  local value_type = type(value)\n  local mapping = value_type == 'string' and value or value[2]\n  local mode = value[1] ~= '' and 'mode: ' .. value[1] or ''\n  local line = fmt('\"%s\", %s', mapping, mode)\n  return line\nend\n\nlocal function format_cmd(value)\n  return fmt('\"%s\"', value)\nend\n\n---format a configuration value of unknown type into a string or list of strings\n---@param key string\n---@param value any\n---@return string|string[]\nlocal function format_values(key, value)\n  local value_type = type(value)\n  if key == 'path' then\n    local is_opt = value:match 'opt' ~= nil\n    return { fmt('\"%s\"', vim.fn.fnamemodify(value, ':~')), fmt('opt: %s', vim.inspect(is_opt)) }\n  elseif key == 'url' then\n    return fmt('\"%s\"', value)\n  elseif key == 'keys' then\n    return unpack_config_value(value, value_type, format_keys)\n  elseif key == 'commands' then\n    return unpack_config_value(value, value_type, format_cmd)\n  else\n    return vim.inspect(value)\n  end\nend\n\nlocal status_keys = {\n  'path',\n  'url',\n  'commands',\n  'keys',\n  'module',\n  'as',\n  'ft',\n  'event',\n  'rocks',\n  'branch',\n  'commit',\n  'tag',\n  'lock',\n}\n\nlocal config = nil\nlocal keymaps = {\n  quit = { rhs = '<cmd>lua require\"packer.display\".quit()<cr>', action = 'quit' },\n  diff = { rhs = '<cmd>lua require\"packer.display\".diff()<cr>', action = 'show the diff' },\n  toggle_update = { rhs = '<cmd>lua require\"packer.display\".toggle_update()<cr>', action = 'toggle update' },\n  continue = { rhs = '<cmd>lua require\"packer.display\".continue()<cr>', action = 'continue with updates' },\n  toggle_info = {\n    rhs = '<cmd>lua require\"packer.display\".toggle_info()<cr>',\n    action = 'show more info',\n  },\n  prompt_revert = {\n    rhs = '<cmd>lua require\"packer.display\".prompt_revert()<cr>',\n    action = 'revert an update',\n  },\n  retry = {\n    rhs = '<cmd>lua require\"packer.display\".retry()<cr>',\n    action = 'retry failed operations',\n  },\n}\n\n--- The order of the keys in a dict-like table isn't guaranteed, meaning the display window can\n--- potentially show the keybindings in a different order every time\nlocal default_keymap_display_order = {\n  'quit',\n  'toggle_info',\n  'diff',\n  'prompt_revert',\n  'retry',\n}\n\n--- Utility function to prompt a user with a question in a floating window\nlocal function prompt_user(headline, body, callback)\n  if not interactive(config) then\n    callback(true)\n    return\n  end\n\n  local buf = api.nvim_create_buf(false, true)\n  local longest_line = 0\n  for _, line in ipairs(body) do\n    local line_length = string.len(line)\n    if line_length > longest_line then\n      longest_line = line_length\n    end\n  end\n\n  local width = math.min(longest_line + 2, math.floor(0.9 * vim.o.columns))\n  local height = #body + 3\n  local x = (vim.o.columns - width) / 2.0\n  local y = (vim.o.lines - height) / 2.0\n  local pad_width = math.max(math.floor((width - string.len(headline)) / 2.0), 0)\n  api.nvim_buf_set_lines(\n    buf,\n    0,\n    -1,\n    true,\n    vim.list_extend({\n      string.rep(' ', pad_width) .. headline .. string.rep(' ', pad_width),\n      '',\n    }, body)\n  )\n  api.nvim_buf_set_option(buf, 'modifiable', false)\n  local opts = {\n    relative = 'editor',\n    width = width,\n    height = height,\n    col = x,\n    row = y,\n    focusable = false,\n    style = 'minimal',\n    border = config.prompt_border,\n    noautocmd = true,\n  }\n\n  local win = api.nvim_open_win(buf, false, opts)\n  local check = vim.loop.new_prepare()\n  local prompted = false\n  vim.loop.prepare_start(\n    check,\n    vim.schedule_wrap(function()\n      if not api.nvim_win_is_valid(win) then\n        return\n      end\n      vim.loop.prepare_stop(check)\n      if not prompted then\n        prompted = true\n        local ans = string.lower(vim.fn.input 'OK to remove? [y/N] ') == 'y'\n        api.nvim_win_close(win, true)\n        callback(ans)\n      end\n    end)\n  )\nend\n\nlocal make_update_msg = function(symbol, status, plugin_name, plugin)\n  return fmt(\n    ' %s %s %s: %s..%s',\n    symbol,\n    status,\n    plugin_name,\n    plugin.revs[1],\n    plugin.revs[2]\n  )\nend\n\nlocal display = {}\nlocal display_mt = {\n  --- Check if we have a valid display window\n  valid_display = function(self)\n    return self and self.interactive and api.nvim_buf_is_valid(self.buf) and api.nvim_win_is_valid(self.win)\n  end,\n  --- Update the text of the display buffer\n  set_lines = function(self, start_idx, end_idx, lines)\n    if not self:valid_display() then\n      return\n    end\n    api.nvim_buf_set_option(self.buf, 'modifiable', true)\n    api.nvim_buf_set_lines(self.buf, start_idx, end_idx, true, lines)\n    api.nvim_buf_set_option(self.buf, 'modifiable', false)\n  end,\n  get_lines = function(self, start_idx, end_idx)\n    if not self:valid_display() then\n      return\n    end\n    return api.nvim_buf_get_lines(self.buf, start_idx, end_idx, true)\n  end,\n  get_current_line = function(self)\n    if not self:valid_display() then\n      return\n    end\n    return api.nvim_get_current_line()\n  end,\n  --- Start displaying a new task\n  task_start = vim.schedule_wrap(function(self, plugin, message)\n    if not self:valid_display() then\n      return\n    end\n    if self.marks[plugin] then\n      self:task_update(plugin, message)\n      return\n    end\n    display.status.running = true\n    self:set_lines(config.header_lines, config.header_lines, {\n      fmt(' %s %s: %s', config.working_sym, plugin, message),\n    })\n    self.marks[plugin] = set_extmark(self.buf, self.ns, nil, config.header_lines, 0)\n  end),\n\n  --- Decrement the count of active operations in the headline\n  decrement_headline_count = vim.schedule_wrap(function(self)\n    if not self:valid_display() then\n      return\n    end\n    local headline = api.nvim_buf_get_lines(self.buf, 0, 1, false)[1]\n    local count_start, count_end = string.find(headline, '%d+')\n    local count = tonumber(string.sub(headline, count_start, count_end))\n    local updated_headline = string.sub(headline, 1, count_start - 1)\n      .. tostring(count - 1)\n      .. string.sub(headline, count_end + 1)\n    api.nvim_buf_set_option(self.buf, 'modifiable', true)\n    api.nvim_buf_set_lines(self.buf, 0, 1, false, { updated_headline })\n    api.nvim_buf_set_option(self.buf, 'modifiable', false)\n  end),\n\n  --- Update a task as having successfully completed\n  task_succeeded = vim.schedule_wrap(function(self, plugin, message)\n    if not self:valid_display() then\n      return\n    end\n    local line, _ = get_extmark_by_id(self.buf, self.ns, self.marks[plugin])\n    self:set_lines(line[1], line[1] + 1, { fmt(' %s %s: %s', config.done_sym, plugin, message) })\n    api.nvim_buf_del_extmark(self.buf, self.ns, self.marks[plugin])\n    self.marks[plugin] = nil\n    self:decrement_headline_count()\n  end),\n\n  --- Update a task as having unsuccessfully failed\n  task_failed = vim.schedule_wrap(function(self, plugin, message)\n    if not self:valid_display() then\n      return\n    end\n    local line, _ = get_extmark_by_id(self.buf, self.ns, self.marks[plugin])\n    self:set_lines(line[1], line[1] + 1, { fmt(' %s %s: %s', config.error_sym, plugin, message) })\n    api.nvim_buf_del_extmark(self.buf, self.ns, self.marks[plugin])\n    self.marks[plugin] = nil\n    self:decrement_headline_count()\n  end),\n\n  --- Update the status message of a task in progress\n  task_update = vim.schedule_wrap(function(self, plugin, message)\n    if not self:valid_display() then\n      return\n    end\n    if not self.marks[plugin] then\n      return\n    end\n    local line, _ = get_extmark_by_id(self.buf, self.ns, self.marks[plugin])\n    self:set_lines(line[1], line[1] + 1, { fmt(' %s %s: %s', config.working_sym, plugin, message) })\n    set_extmark(self.buf, self.ns, self.marks[plugin], line[1], 0)\n  end),\n\n  open_preview = function(_, commit, lines)\n    if not lines or #lines < 1 then\n      return log.warn 'No diff available'\n    end\n    vim.cmd('pedit ' .. commit)\n    vim.cmd [[wincmd P]]\n    vim.wo.previewwindow = true\n    vim.bo.buftype = 'nofile'\n    vim.bo.buflisted = false\n    vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)\n    vim.api.nvim_buf_set_keymap(0, 'n', 'q', '<cmd>close!<CR>', { silent = true, noremap = true, nowait = true })\n    vim.bo.filetype = 'git'\n  end,\n\n  --- Update the text of the headline message\n  update_headline_message = vim.schedule_wrap(function(self, message)\n    if not self:valid_display() then\n      return\n    end\n    local headline = config.title .. ' - ' .. message\n    local width = api.nvim_win_get_width(self.win) - 2\n    local pad_width = math.max(math.floor((width - string.len(headline)) / 2.0), 0)\n    self:set_lines(0, config.header_lines - 1, { string.rep(' ', pad_width) .. headline })\n  end),\n\n  --- Setup new syntax group links for the status window\n  setup_status_syntax = function(self)\n    local highlights = {\n      'hi def link packerStatus         Type',\n      'hi def link packerStatusCommit   Constant',\n      'hi def link packerStatusSuccess  Constant',\n      'hi def link packerStatusFail     ErrorMsg',\n      'hi def link packerPackageName    Label',\n      'hi def link packerPackageNotLoaded    Comment',\n      'hi def link packerString         String',\n      'hi def link packerBool Boolean',\n      'hi def link packerBreakingChange WarningMsg',\n    }\n    for _, c in ipairs(highlights) do\n      vim.cmd(c)\n    end\n  end,\n\n  setup_profile_syntax = function(_)\n    local highlights = {\n      'hi def link packerTimeHigh ErrorMsg',\n      'hi def link packerTimeMedium WarningMsg',\n      'hi def link packerTimeLow String',\n      'hi def link packerTimeTrivial Comment',\n    }\n    for _, c in ipairs(highlights) do\n      vim.cmd(c)\n    end\n  end,\n\n  status = vim.schedule_wrap(function(self, plugins)\n    if not self:valid_display() then\n      return\n    end\n    self:setup_status_syntax()\n    self:update_headline_message(fmt('Total plugins: %d', vim.tbl_count(plugins)))\n\n    local plugs = {}\n    local lines = {}\n\n    local padding = string.rep(' ', 3)\n    local rtps = api.nvim_list_runtime_paths()\n    for plug_name, plug_conf in pairs(plugins) do\n      local load_state = plug_conf.loaded and ''\n        or vim.tbl_contains(rtps, plug_conf.path) and ' (manually loaded)'\n        or ' (not loaded)'\n      local header_lines = { fmt(' %s %s', config.item_sym, plug_name) .. load_state }\n      local config_lines = {}\n      for key, value in pairs(plug_conf) do\n        if vim.tbl_contains(status_keys, key) then\n          local details = format_values(key, value)\n          if type(details) == 'string' then\n            -- insert a position one so that one line details appear above multiline ones\n            table.insert(config_lines, 1, fmt('%s%s: %s', padding, key, details))\n          else\n            details = vim.tbl_map(function(line)\n              return padding .. line\n            end, details)\n            vim.list_extend(config_lines, { fmt('%s%s: ', padding, key), unpack(details) })\n          end\n          plugs[plug_name] = { lines = config_lines, displayed = false }\n        end\n      end\n      vim.list_extend(lines, header_lines)\n    end\n    table.sort(lines)\n    self.items = plugs\n    self:set_lines(config.header_lines, -1, lines)\n  end),\n\n  is_previewing = function(self)\n    local opts = self.opts or {}\n    return opts.preview_updates\n  end,\n\n  has_changes = function(self, plugin)\n    if plugin.type ~= plugin_utils.git_plugin_type or plugin.revs[1] == plugin.revs[2] then\n      return false\n    end\n    if self:is_previewing() and plugin.commit ~= nil then\n      return false\n    end\n    return true\n  end,\n\n  --- Display the final results of an operation\n  final_results = vim.schedule_wrap(function(self, results, time, opts)\n    self.opts = opts\n    if not self:valid_display() then\n      return\n    end\n    local keymap_display_order = {}\n    vim.list_extend(keymap_display_order, default_keymap_display_order)\n    self.results = results\n    self:setup_status_syntax()\n    display.status.running = false\n    time = tonumber(time)\n    self:update_headline_message(fmt('finished in %.3fs', time))\n    local raw_lines = {}\n    local item_order = {}\n    local rocks_items = {}\n    if results.removals then\n      for _, plugin_dir in ipairs(results.removals) do\n        table.insert(item_order, plugin_dir)\n        table.insert(raw_lines, fmt(' %s Removed %s', config.removed_sym, plugin_dir))\n      end\n    end\n\n    if results.moves then\n      for plugin, result in pairs(results.moves) do\n        table.insert(item_order, plugin)\n        table.insert(\n          raw_lines,\n          fmt(\n            ' %s %s %s: %s %s %s',\n            result.result.ok and config.done_sym or config.error_sym,\n            result.result.ok and 'Moved' or 'Failed to move',\n            plugin,\n            result.from,\n            config.moved_sym,\n            result.to\n          )\n        )\n      end\n    end\n\n    display.status.any_failed_install = false\n    display.status.failed_update_list = {}\n\n    if results.installs then\n      for plugin, result in pairs(results.installs) do\n        table.insert(item_order, plugin)\n        table.insert(\n          raw_lines,\n          fmt(\n            ' %s %s %s',\n            result.ok and config.done_sym or config.error_sym,\n            result.ok and 'Installed' or 'Failed to install',\n            plugin\n          )\n        )\n        display.status.any_failed_install = display.status.any_failed_install or not result.ok\n      end\n    end\n\n    if results.updates then\n      local status_msg = 'Updated'\n      if self:is_previewing() then\n        status_msg = 'Can update'\n        table.insert(keymap_display_order, 1, 'continue')\n        table.insert(keymap_display_order, 2, 'toggle_update')\n      end\n      for plugin_name, result in pairs(results.updates) do\n        local plugin = results.plugins[plugin_name]\n        local message = {}\n        local actual_update = true\n        local failed_update = false\n        if result.ok then\n          if self:has_changes(plugin) then\n            table.insert(item_order, plugin_name)\n            table.insert(\n              message,\n              make_update_msg(config.done_sym, status_msg, plugin_name, plugin)\n            )\n          else\n            actual_update = false\n            table.insert(message, fmt(' %s %s is already up to date', config.done_sym, plugin_name))\n          end\n        else\n          failed_update = true\n          actual_update = false\n          table.insert(display.status.failed_update_list, plugin.short_name)\n          table.insert(item_order, plugin_name)\n          table.insert(message, fmt(' %s Failed to update %s', config.error_sym, plugin_name))\n        end\n\n        plugin.actual_update = actual_update\n        if actual_update or failed_update then\n          vim.list_extend(raw_lines, message)\n        end\n      end\n    end\n\n    if results.luarocks then\n      if results.luarocks.installs then\n        for package, result in pairs(results.luarocks.installs) do\n          if result.err then\n            rocks_items[package] = { lines = strip_newlines(result.err.output.data.stderr) }\n          end\n\n          table.insert(\n            raw_lines,\n            fmt(\n              ' %s %s %s',\n              result.ok and config.done_sym or config.error_sym,\n              result.ok and 'Installed' or 'Failed to install',\n              package\n            )\n          )\n          display.status.any_failed_install = display.status.any_failed_install or not result.ok\n        end\n      end\n\n      if results.luarocks.removals then\n        for package, result in pairs(results.luarocks.removals) do\n          if result.err then\n            rocks_items[package] = { lines = strip_newlines(result.err.output.data.stderr) }\n          end\n\n          table.insert(\n            raw_lines,\n            fmt(\n              ' %s %s %s',\n              result.ok and config.done_sym or config.error_sym,\n              result.ok and 'Removed' or 'Failed to remove',\n              package\n            )\n          )\n        end\n      end\n    end\n\n    if #raw_lines == 0 then\n      table.insert(raw_lines, ' Everything already up to date!')\n    end\n\n    table.insert(raw_lines, '')\n    local show_retry = display.status.any_failed_install or #display.status.failed_update_list > 0\n    for _, keymap in ipairs(keymap_display_order) do\n      if keymaps[keymap].lhs then\n        if not (keymap == 'retry') or show_retry then\n          table.insert(raw_lines, fmt(\" Press '%s' to %s\", keymaps[keymap].lhs, keymaps[keymap].action))\n        end\n      end\n    end\n\n    -- Ensure there are no newlines\n    local lines = strip_newlines(raw_lines)\n    self:set_lines(config.header_lines, -1, lines)\n    local plugins = {}\n    for plugin_name, plugin in pairs(results.plugins) do\n      local plugin_data = { displayed = false, lines = {}, spec = plugin }\n      if plugin.output then\n        if plugin.output.err and #plugin.output.err > 0 then\n          table.insert(plugin_data.lines, '  Errors:')\n          for _, line in ipairs(plugin.output.err) do\n            line = vim.trim(line)\n            if line:find '\\n' then\n              for sub_line in line:gmatch '[^\\r\\n]+' do\n                table.insert(plugin_data.lines, '    ' .. sub_line)\n              end\n            else\n              table.insert(plugin_data.lines, '    ' .. line)\n            end\n          end\n        end\n      end\n\n      if plugin.messages and #plugin.messages > 0 then\n        table.insert(plugin_data.lines, fmt('  URL: %s', plugin.url))\n        table.insert(plugin_data.lines, '  Commits:')\n        for _, msg in ipairs(plugin.messages) do\n          for _, line in ipairs(vim.split(msg, '\\n')) do\n            table.insert(plugin_data.lines, string.rep(' ', 4) .. line)\n          end\n        end\n\n        table.insert(plugin_data.lines, '')\n      end\n\n      if plugin.breaking_commits and #plugin.breaking_commits > 0 then\n        vim.cmd('syntax match packerBreakingChange \"' .. plugin_name .. '\" containedin=packerStatusSuccess')\n        for _, commit_hash in ipairs(plugin.breaking_commits) do\n          log.warn('Potential breaking change in commit ' .. commit_hash .. ' of ' .. plugin_name)\n          vim.cmd('syntax match packerBreakingChange \"' .. commit_hash .. '\" containedin=packerHash')\n        end\n      end\n\n      plugins[plugin_name] = plugin_data\n    end\n\n    self.items = vim.tbl_extend('keep', plugins, rocks_items)\n    self.item_order = item_order\n    if config.show_all_info then\n      self:show_all_info()\n    end\n  end),\n\n  --- Toggle the display of detailed information for all plugins in the final results display\n  show_all_info = function(self)\n    if not self:valid_display() then\n      return\n    end\n    if next(self.items) == nil then\n      log.info 'Operations are still running; plugin info is not ready yet'\n      return\n    end\n\n    local line = config.header_lines + 1\n    for _, plugin_name in pairs(self.item_order) do\n      local plugin_data = self.items[plugin_name]\n      if plugin_data and plugin_data.spec.actual_update and #plugin_data.lines > 0 then\n        local next_line\n        if config.compact then\n          next_line = line + 1\n          plugin_data.displayed = false\n        else\n          self:set_lines(line, line, plugin_data.lines)\n          next_line = line + #plugin_data.lines + 1\n          plugin_data.displayed = true\n        end\n        self.marks[plugin_name] = {\n          start = set_extmark(self.buf, self.ns, nil, line - 1, 0),\n          end_ = set_extmark(self.buf, self.ns, nil, next_line - 1, 0),\n        }\n        line = next_line\n      else\n        line = line + 1\n      end\n    end\n  end,\n\n  profile_output = function(self, output)\n    self:setup_profile_syntax()\n    local result = {}\n    for i, line in ipairs(output) do\n      result[i] = string.rep(' ', 2) .. line\n    end\n    self:set_lines(config.header_lines, -1, result)\n  end,\n\n  --- Toggle the display of detailed information for a plugin in the final results display\n  toggle_info = function(self)\n    if not self:valid_display() then\n      return\n    end\n    if self.items == nil or next(self.items) == nil then\n      log.info 'Operations are still running; plugin info is not ready yet'\n      return\n    end\n\n    local plugin_name, cursor_pos = self:find_nearest_plugin()\n    if plugin_name == nil then\n      log.warn 'No plugin selected!'\n      return\n    end\n\n    local plugin_data = self.items[plugin_name]\n    if plugin_data.displayed then\n      self:set_lines(cursor_pos[1], cursor_pos[1] + #plugin_data.lines, {})\n      plugin_data.displayed = false\n    elseif #plugin_data.lines > 0 then\n      self:set_lines(cursor_pos[1], cursor_pos[1], plugin_data.lines)\n      plugin_data.displayed = true\n    else\n      log.info('No further information for ' .. plugin_name)\n    end\n\n    api.nvim_win_set_cursor(0, cursor_pos)\n  end,\n\n  diff = function(self)\n    if not self:valid_display() then\n      return\n    end\n    if next(self.items) == nil then\n      log.info 'Operations are still running; plugin info is not ready yet'\n      return\n    end\n\n    local plugin_name, _ = self:find_nearest_plugin()\n    if plugin_name == nil then\n      log.warn 'No plugin selected!'\n      return\n    end\n\n    if not self.items[plugin_name] or not self.items[plugin_name].spec then\n      log.warn 'Plugin not available!'\n      return\n    end\n\n    local plugin_data = self.items[plugin_name].spec\n    local current_line = self:get_current_line()\n    local commit_pattern = [[[0-9a-f]\\{7,9}]]\n    local commit_single_pattern = string.format([[\\<%s\\>]], commit_pattern)\n    local commit_range_pattern = string.format([[\\<%s\\.\\.%s\\>]], commit_pattern, commit_pattern)\n    local commit = vim.fn.matchstr(current_line, commit_range_pattern)\n    if commit == '' then\n      commit = vim.fn.matchstr(current_line, commit_single_pattern)\n    end\n    if commit == '' then\n      log.warn 'Unable to find the diff for this line'\n      return\n    end\n    plugin_data.diff(commit, function(lines, err)\n      if err then\n        return log.warn 'Unable to get diff!'\n      end\n      vim.schedule(function()\n        self:open_preview(commit, lines)\n      end)\n    end)\n  end,\n\n  toggle_update = function(self)\n    if not self:is_previewing() then\n      return\n    end\n    local plugin_name, _ = self:find_nearest_plugin()\n    local plugin = self.items[plugin_name]\n    if not plugin then\n      log.warn 'Plugin not available!'\n      return\n    end\n    local plugin_data = plugin.spec\n    if not plugin_data.actual_update then\n      return\n    end\n    plugin_data.ignore_update = not plugin_data.ignore_update\n    self:toggle_plugin_text(plugin_name, plugin_data)\n  end,\n\n  toggle_plugin_text = function(self, plugin_name, plugin_data)\n    local mark_ids = self.marks[plugin_name]\n    local start_idx = get_extmark_by_id(self.buf, self.ns, mark_ids.start)[1]\n    local symbol\n    local status_msg\n    if plugin_data.ignore_update then\n      status_msg = [[Won't update]]\n      symbol = config.item_sym\n    else\n      status_msg = 'Can update'\n      symbol = config.done_sym\n    end\n    self:set_lines(\n      start_idx,\n      start_idx + 1,\n      {make_update_msg(symbol, status_msg, plugin_name, plugin_data)}\n    )\n    -- NOTE we need to reset the mark\n    self.marks[plugin_name].start = set_extmark(self.buf, self.ns, nil, start_idx, 0)\n  end,\n\n  continue = function(self)\n    if not self:is_previewing() then\n      return\n    end\n    local plugins = {}\n    for plugin_name, _ in pairs(self.results.updates) do\n      local plugin_data = self.items[plugin_name].spec\n      if plugin_data.actual_update and not plugin_data.ignore_update then\n        table.insert(plugins, plugin_data.short_name)\n      end\n    end\n    if #plugins > 0 then\n      require('packer').update({pull_head = true, preview_updates = false}, unpack(plugins))\n    else\n      log.warn 'No plugins selected!'\n    end\n  end,\n\n  --- Prompt a user to revert the latest update for a plugin\n  prompt_revert = function(self)\n    if not self:valid_display() then\n      return\n    end\n    if next(self.items) == nil then\n      log.info 'Operations are still running; plugin info is not ready yet'\n      return\n    end\n\n    local plugin_name, _ = self:find_nearest_plugin()\n    if plugin_name == nil then\n      log.warn 'No plugin selected!'\n      return\n    end\n\n    local plugin_data = self.items[plugin_name].spec\n    if plugin_data.actual_update then\n      prompt_user('Revert update for ' .. plugin_name .. '?', {\n        'Do you want to revert '\n          .. plugin_name\n          .. ' from '\n          .. plugin_data.revs[2]\n          .. ' to '\n          .. plugin_data.revs[1]\n          .. '?',\n      }, function(ans)\n        if ans then\n          local r = plugin_data.revert_last()\n          if r.ok then\n            log.info('Reverted update for ' .. plugin_name)\n          else\n            log.error('Reverting update for ' .. plugin_name .. ' failed!')\n          end\n        end\n      end)\n    else\n      log.warn(plugin_name .. \" wasn't updated; can't revert!\")\n    end\n  end,\n\n  is_plugin_line = function(self, line)\n    for _, sym in pairs { config.item_sym, config.done_sym, config.working_sym, config.error_sym } do\n      if string.find(line, sym, 1, true) then\n        return true\n      end\n    end\n    return false\n  end,\n\n  --- Heuristically find the plugin nearest to the cursor for displaying detailed information\n  find_nearest_plugin = function(self)\n    if not self:valid_display() then\n      return\n    end\n\n    local current_cursor_pos = api.nvim_win_get_cursor(0)\n    local nb_lines = api.nvim_buf_line_count(0)\n    local cursor_pos_y = math.max(current_cursor_pos[1], config.header_lines + 1)\n    if cursor_pos_y > nb_lines then\n      return\n    end\n    for i = cursor_pos_y, 1, -1 do\n      local curr_line = api.nvim_buf_get_lines(0, i - 1, i, true)[1]\n      if self:is_plugin_line(curr_line) then\n        for name, _ in pairs(self.items) do\n          if string.find(curr_line, name, 1, true) then\n            return name, { i, 0 }\n          end\n        end\n      end\n    end\n  end,\n}\n\ndisplay_mt.__index = display_mt\n\nlocal function look_back(str)\n  return string.format([[\\(%s\\)\\@%d<=]], str, #str)\nend\n\n-- TODO: Option for no colors\nlocal function make_filetype_cmds(working_sym, done_sym, error_sym)\n  return {\n    -- Adapted from https://github.com/kristijanhusak/vim-packager\n    'setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap nospell nonumber norelativenumber nofoldenable signcolumn=no',\n    'syntax clear',\n    'syn match packerWorking /^ ' .. working_sym .. '/',\n    'syn match packerSuccess /^ ' .. done_sym .. '/',\n    'syn match packerFail /^ ' .. error_sym .. '/',\n    'syn match packerStatus /^+.*—\\\\zs\\\\s.*$/',\n    'syn match packerStatusSuccess /' .. look_back('^ ' .. done_sym) .. '\\\\s.*$/',\n    'syn match packerStatusFail /' .. look_back('^ ' .. error_sym) .. '\\\\s.*$/',\n    'syn match packerStatusCommit /^\\\\*.*—\\\\zs\\\\s.*$/',\n    'syn match packerHash /\\\\(\\\\s\\\\)[0-9a-f]\\\\{7,8}\\\\(\\\\s\\\\)/',\n    'syn match packerRelDate /([^)]*)$/',\n    'syn match packerProgress /\\\\[\\\\zs[\\\\=]*/',\n    'syn match packerOutput /\\\\(Output:\\\\)\\\\|\\\\(Commits:\\\\)\\\\|\\\\(Errors:\\\\)/',\n    [[syn match packerTimeHigh /\\d\\{3\\}\\.\\d\\+ms/]],\n    [[syn match packerTimeMedium /\\d\\{2\\}\\.\\d\\+ms/]],\n    [[syn match packerTimeLow /\\d\\.\\d\\+ms/]],\n    [[syn match packerTimeTrivial /0\\.\\d\\+ms/]],\n    [[syn match packerPackageNotLoaded /(not loaded)$/]],\n    [[syn match packerString /\\v(''|\"\"|(['\"]).{-}[^\\\\]\\2)/]],\n    [[syn match packerBool /\\<\\(false\\|true\\)\\>/]],\n    [[syn match packerPackageName /^\\ • \\zs[^ ]*/]],\n    'hi def link packerWorking        SpecialKey',\n    'hi def link packerSuccess        Question',\n    'hi def link packerFail           ErrorMsg',\n    'hi def link packerHash           Identifier',\n    'hi def link packerRelDate        Comment',\n    'hi def link packerProgress       Boolean',\n    'hi def link packerOutput         Type',\n  }\nend\n\ndisplay.cfg = function(_config)\n  config = _config.display\n  if config.keybindings then\n    for name, lhs in pairs(config.keybindings) do\n      if keymaps[name] then\n        keymaps[name].lhs = lhs\n      end\n    end\n  end\n  config.filetype_cmds = make_filetype_cmds(config.working_sym, config.done_sym, config.error_sym)\nend\n\n--- Utility to make the initial display buffer header\nlocal function make_header(disp)\n  local width = api.nvim_win_get_width(0)\n  local pad_width = math.floor((width - string.len(config.title)) / 2.0)\n  api.nvim_buf_set_lines(disp.buf, 0, 1, true, {\n    string.rep(' ', pad_width) .. config.title,\n    ' ' .. string.rep(config.header_sym, width - 2),\n  })\nend\n\n--- Initialize options, settings, and keymaps for display windows\nlocal function setup_window(disp)\n  api.nvim_buf_set_option(disp.buf, 'filetype', 'packer')\n  api.nvim_buf_set_name(disp.buf, '[packer]')\n  for _, m in pairs(keymaps) do\n    if m.lhs then\n      api.nvim_buf_set_keymap(disp.buf, 'n', m.lhs, m.rhs, { nowait = true, silent = true })\n    end\n  end\n  for _, c in ipairs(config.filetype_cmds) do\n    vim.cmd(c)\n  end\nend\n\n--- Open a new display window\n-- Takes either a string representing a command or a function returning a (window, buffer) pair.\ndisplay.open = function(opener)\n  if display.status.disp then\n    if api.nvim_win_is_valid(display.status.disp.win) then\n      api.nvim_win_close(display.status.disp.win, true)\n    end\n\n    display.status.disp = nil\n  end\n\n  local disp = setmetatable({}, display_mt)\n  disp.marks = {}\n  disp.plugins = {}\n  disp.interactive = interactive(config)\n\n  if disp.interactive then\n    if type(opener) == 'string' then\n      vim.cmd(opener)\n      disp.win = api.nvim_get_current_win()\n      disp.buf = api.nvim_get_current_buf()\n    else\n      local status, win, buf = opener '[packer]'\n      if not status then\n        log.error('Failure running opener function: ' .. vim.inspect(win))\n        error(win)\n      end\n\n      disp.win = win\n      disp.buf = buf\n    end\n\n    disp.ns = api.nvim_create_namespace ''\n    make_header(disp)\n    setup_window(disp)\n    display.status.disp = disp\n  end\n\n  return disp\nend\n\ndisplay.status = { running = false, disp = nil }\n\n--- Close a display window and signal that any running operations should terminate\ndisplay.quit = function()\n  display.status.running = false\n  vim.fn.execute('q!', 'silent')\nend\n\ndisplay.toggle_info = function()\n  if display.status.disp then\n    display.status.disp:toggle_info()\n  end\nend\n\ndisplay.diff = function()\n  if display.status.disp then\n    display.status.disp:diff()\n  end\nend\n\ndisplay.toggle_update = function()\n  if display.status.disp then\n    display.status.disp:toggle_update()\n  end\nend\n\ndisplay.continue = function()\n  if display.status.disp then\n    display.status.disp:continue()\n  end\nend\n\ndisplay.prompt_revert = function()\n  if display.status.disp then\n    display.status.disp:prompt_revert()\n  end\nend\n\ndisplay.retry = function()\n  if display.status.any_failed_install then\n    require('packer').install()\n  elseif #display.status.failed_update_list > 0 then\n    require('packer').update(unpack(display.status.failed_update_list))\n  end\nend\n\n--- Async prompt_user\ndisplay.ask_user = a.wrap(prompt_user)\n\nreturn display\n"
  },
  {
    "path": "lua/packer/handlers.lua",
    "content": "local config = nil\n\nlocal function cfg(_config)\n  config = _config\nend\n\nlocal handlers = {\n  cfg = cfg,\n}\n\nreturn handlers\n"
  },
  {
    "path": "lua/packer/install.lua",
    "content": "local a = require 'packer.async'\nlocal log = require 'packer.log'\nlocal util = require 'packer.util'\nlocal display = require 'packer.display'\nlocal plugin_utils = require 'packer.plugin_utils'\n\nlocal fmt = string.format\nlocal async = a.sync\nlocal await = a.wait\n\nlocal config = nil\n\nlocal function install_plugin(plugin, display_win, results)\n  local plugin_name = util.get_plugin_full_name(plugin)\n  return async(function()\n    display_win:task_start(plugin_name, 'installing...')\n    -- TODO: If the user provided a custom function as an installer, we would like to use pcall\n    -- here. Need to figure out how that integrates with async code\n    local r = await(plugin.installer(display_win))\n    r = r:and_then(await, plugin_utils.post_update_hook(plugin, display_win))\n    if r.ok then\n      display_win:task_succeeded(plugin_name, 'installed')\n      log.debug('Installed ' .. plugin_name)\n    else\n      display_win:task_failed(plugin_name, 'failed to install')\n      log.debug(fmt('Failed to install %s: %s', plugin_name, vim.inspect(r.err)))\n    end\n\n    results.installs[plugin_name] = r\n    results.plugins[plugin_name] = plugin\n  end)\nend\n\nlocal function do_install(_, plugins, missing_plugins, results)\n  results = results or {}\n  results.installs = results.installs or {}\n  results.plugins = results.plugins or {}\n  local display_win = nil\n  local tasks = {}\n  if #missing_plugins > 0 then\n    display_win = display.open(config.display.open_fn or config.display.open_cmd)\n    for _, v in ipairs(missing_plugins) do\n      if not plugins[v].disable then\n        table.insert(tasks, install_plugin(plugins[v], display_win, results))\n      end\n    end\n  end\n\n  return tasks, display_win\nend\n\nlocal function cfg(_config)\n  config = _config\nend\n\nlocal install = setmetatable({ cfg = cfg }, { __call = do_install })\n\nreturn install\n"
  },
  {
    "path": "lua/packer/jobs.lua",
    "content": "-- Interface with Neovim job control and provide a simple job sequencing structure\nlocal split = vim.split\nlocal loop = vim.loop\nlocal a = require 'packer.async'\nlocal log = require 'packer.log'\nlocal result = require 'packer.result'\n\n--- Utility function to make a \"standard\" logging callback for a given set of tables\n-- Arguments:\n-- - err_tbl: table to which err messages will be logged\n-- - data_tbl: table to which data (non-err messages) will be logged\n-- - pipe: the pipe for which this callback will be used. Passed in so that we can make sure all\n--      output flushes before finishing reading\n-- - disp: optional packer.display object for updating task status. Requires `name`\n-- - name: optional string name for a current task. Used to update task status\nlocal function make_logging_callback(err_tbl, data_tbl, pipe, disp, name)\n  return function(err, data)\n    if err then\n      table.insert(err_tbl, vim.trim(err))\n    end\n    if data ~= nil then\n      local trimmed = vim.trim(data)\n      table.insert(data_tbl, trimmed)\n      if disp then\n        disp:task_update(name, split(trimmed, '\\n')[1])\n      end\n    else\n      loop.read_stop(pipe)\n      loop.close(pipe)\n    end\n  end\nend\n\n--- Utility function to make a table for capturing output with \"standard\" structure\nlocal function make_output_table()\n  return { err = { stdout = {}, stderr = {} }, data = { stdout = {}, stderr = {} } }\nend\n\n--- Utility function to merge stdout and stderr from two tables with \"standard\" structure (either\n--  the err or data subtables, specifically)\nlocal function extend_output(to, from)\n  vim.list_extend(to.stdout, from.stdout)\n  vim.list_extend(to.stderr, from.stderr)\n  return to\nend\n\n--- Wrapper for vim.loop.spawn. Takes a command, options, and callback just like vim.loop.spawn, but\n--  (1) makes an async function and (2) ensures that all output from the command has been flushed\n--  before calling the callback\nlocal spawn = a.wrap(function(cmd, options, callback)\n  local handle = nil\n  local timer = nil\n  handle, pid = loop.spawn(cmd, options, function(exit_code, signal)\n    handle:close()\n    if timer ~= nil then\n      timer:stop()\n      timer:close()\n    end\n\n    loop.close(options.stdio[1])\n    local check = loop.new_check()\n    loop.check_start(check, function()\n      for _, pipe in pairs(options.stdio) do\n        if not loop.is_closing(pipe) then\n          return\n        end\n      end\n      loop.check_stop(check)\n      callback(exit_code, signal)\n    end)\n  end)\n\n  if options.stdio then\n    for i, pipe in pairs(options.stdio) do\n      if options.stdio_callbacks[i] then\n        loop.read_start(pipe, options.stdio_callbacks[i])\n      end\n    end\n  end\n\n  if handle == nil then \n      -- pid is an error string in this case \n      log.error(string.format(\"Failed spawning command: %s because %s\", cmd, pid))\n      callback(-1, pid)\n      return \n  end\n\n  if options.timeout then\n    timer = loop.new_timer()\n    timer:start(options.timeout, 0, function()\n      timer:stop()\n      timer:close()\n      if loop.is_active(handle) then\n        log.warn('Killing ' .. cmd .. ' due to timeout!')\n        loop.process_kill(handle, 'sigint')\n        handle:close()\n        for _, pipe in pairs(options.stdio) do\n          loop.close(pipe)\n        end\n        callback(-9999, 'sigint')\n      end\n    end)\n  end\nend)\n\n--- Utility function to perform a common check for process success and return a result object\nlocal function was_successful(r)\n  if r.exit_code == 0 and (not r.output or not r.output.err or #r.output.err == 0) then\n    return result.ok(r)\n  else\n    return result.err(r)\n  end\nend\n\n--- Main exposed function for the jobs module. Takes a task and options and returns an async\n-- function that will run the task with the given opts via vim.loop.spawn\n-- Arguments:\n--  - task: either a string or table. If string, split, and the first component is treated as the\n--    command. If table, first element is treated as the command. All subsequent elements are passed\n--    as args\n--  - opts: table of options. Can include the keys \"options\" (like the options table passed to\n--    vim.loop.spawn), \"success_test\" (a function, called like `was_successful` (above)),\n--    \"capture_output\" (either a boolean, in which case default output capture is set up and the\n--    resulting tables are included in the result, or a set of tables, in which case output is logged\n--    to the given tables)\nlocal run_job = function(task, opts)\n  return a.sync(function()\n    local options = opts.options or { hide = true }\n    local stdout = nil\n    local stderr = nil\n    local job_result = { exit_code = -1, signal = -1 }\n    local success_test = opts.success_test or was_successful\n    local uv_err\n    local output = make_output_table()\n    local callbacks = {}\n    local output_valid = false\n    if opts.capture_output then\n      if type(opts.capture_output) == 'boolean' then\n        stdout, uv_err = loop.new_pipe(false)\n        if uv_err then\n          log.error('Failed to open stdout pipe: ' .. uv_err)\n          return result.err()\n        end\n\n        stderr, uv_err = loop.new_pipe(false)\n        if uv_err then\n          log.error('Failed to open stderr pipe: ' .. uv_err)\n          return job_result\n        end\n\n        callbacks.stdout = make_logging_callback(output.err.stdout, output.data.stdout, stdout)\n        callbacks.stderr = make_logging_callback(output.err.stderr, output.data.stderr, stderr)\n        output_valid = true\n      elseif type(opts.capture_output) == 'table' then\n        if opts.capture_output.stdout then\n          stdout, uv_err = loop.new_pipe(false)\n          if uv_err then\n            log.error('Failed to open stdout pipe: ' .. uv_err)\n            return job_result\n          end\n\n          callbacks.stdout = function(err, data)\n            if data ~= nil then\n              opts.capture_output.stdout(err, data)\n            else\n              loop.read_stop(stdout)\n              loop.close(stdout)\n            end\n          end\n        end\n        if opts.capture_output.stderr then\n          stderr, uv_err = loop.new_pipe(false)\n          if uv_err then\n            log.error('Failed to open stderr pipe: ' .. uv_err)\n            return job_result\n          end\n\n          callbacks.stderr = function(err, data)\n            if data ~= nil then\n              opts.capture_output.stderr(err, data)\n            else\n              loop.read_stop(stderr)\n              loop.close(stderr)\n            end\n          end\n        end\n      end\n    end\n\n    if type(task) == 'string' then\n      local split_pattern = '%s+'\n      task = split(task, split_pattern)\n    end\n\n    local cmd = task[1]\n    if opts.timeout then\n      options.timeout = 1000 * opts.timeout\n    end\n\n    options.cwd = opts.cwd\n\n    local stdin = loop.new_pipe(false)\n    options.args = { unpack(task, 2) }\n    options.stdio = { stdin, stdout, stderr }\n    options.stdio_callbacks = { nil, callbacks.stdout, callbacks.stderr }\n\n    local exit_code, signal = a.wait(spawn(cmd, options))\n    job_result = { exit_code = exit_code, signal = signal }\n    if output_valid then\n      job_result.output = output\n    end\n    return success_test(job_result)\n  end)\nend\n\nlocal jobs = {\n  run = run_job,\n  logging_callback = make_logging_callback,\n  output_table = make_output_table,\n  extend_output = extend_output,\n}\n\nreturn jobs\n"
  },
  {
    "path": "lua/packer/load.lua",
    "content": "local packer_load = nil\nlocal cmd = vim.api.nvim_command\nlocal fmt = string.format\n\nlocal function verify_conditions(conds, name)\n  if conds == nil then\n    return true\n  end\n  for _, cond in ipairs(conds) do\n    local success, result\n    if type(cond) == 'boolean' then\n      result = cond\n    elseif type(cond) == 'string' then\n      success, result = pcall(loadstring(cond))\n      if not success then\n        vim.schedule(function()\n          vim.api.nvim_notify(\n            'packer.nvim: Error running cond for ' .. name .. ': ' .. result,\n            vim.log.levels.ERROR,\n            {}\n          )\n        end)\n        return false\n      end\n    end\n    if result == false then\n      return false\n    end\n  end\n  return true\nend\n\nlocal function loader_clear_loaders(plugin)\n  if plugin.commands then\n    for _, del_cmd in ipairs(plugin.commands) do\n      cmd('silent! delcommand ' .. del_cmd)\n    end\n  end\n\n  if plugin.keys then\n    for _, key in ipairs(plugin.keys) do\n      cmd(fmt('silent! %sunmap %s', key[1], key[2]))\n    end\n  end\nend\n\nlocal function loader_apply_config(plugin, name)\n  if plugin.config then\n    for _, config_line in ipairs(plugin.config) do\n      local success, err = pcall(loadstring(config_line), name, plugin)\n      if not success then\n        vim.schedule(function()\n          vim.api.nvim_notify('packer.nvim: Error running config for ' .. name .. ': ' .. err, vim.log.levels.ERROR, {})\n        end)\n      end\n    end\n  end\nend\n\nlocal function loader_apply_wants(plugin, plugins)\n  if plugin.wants then\n    for _, wanted_name in ipairs(plugin.wants) do\n      packer_load({ wanted_name }, {}, plugins)\n    end\n  end\nend\n\nlocal function loader_apply_after(plugin, plugins, name)\n  if plugin.after then\n    for _, after_name in ipairs(plugin.after) do\n      local after_plugin = plugins[after_name]\n      after_plugin.load_after[name] = nil\n      if next(after_plugin.load_after) == nil then\n        packer_load({ after_name }, {}, plugins)\n      end\n    end\n  end\nend\n\nlocal function apply_cause_side_effects(cause)\n  if cause.cmd then\n    local lines = cause.l1 == cause.l2 and '' or (cause.l1 .. ',' .. cause.l2)\n    -- This is a hack to deal with people who haven't recompiled after updating to the new command\n    -- creation logic\n    local bang = ''\n    if type(cause.bang) == 'string' then\n      bang = cause.bang\n    elseif type(cause.bang) == 'boolean' and cause.bang then\n      bang = '!'\n    end\n    cmd(fmt('%s %s%s%s %s', cause.mods or '', lines, cause.cmd, bang, cause.args))\n  elseif cause.keys then\n    local extra = ''\n    while true do\n      local c = vim.fn.getchar(0)\n      if c == 0 then\n        break\n      end\n      extra = extra .. vim.fn.nr2char(c)\n    end\n\n    if cause.prefix then\n      local prefix = vim.v.count ~= 0 and vim.v.count or ''\n      prefix = prefix .. '\"' .. vim.v.register .. cause.prefix\n      if vim.fn.mode 'full' == 'no' then\n        if vim.v.operator == 'c' then\n          prefix = '\u001b' .. prefix\n        end\n        prefix = prefix .. vim.v.operator\n      end\n\n      vim.fn.feedkeys(prefix, 'n')\n    end\n\n    local escaped_keys = vim.api.nvim_replace_termcodes(cause.keys .. extra, true, true, true)\n    vim.api.nvim_feedkeys(escaped_keys, 'm', true)\n  elseif cause.event then\n    cmd(fmt('doautocmd <nomodeline> %s', cause.event))\n  elseif cause.ft then\n    cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'filetypeplugin', cause.ft))\n    cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'filetypeindent', cause.ft))\n    cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'syntaxset', cause.ft))\n  end\nend\n\npacker_load = function(names, cause, plugins, force)\n  local some_unloaded = false\n  local needs_bufread = false\n  local num_names = #names\n  for i = 1, num_names do\n    local plugin = plugins[names[i]]\n    if not plugin then\n      local err_message = 'Error: attempted to load ' .. names[i] .. ' which is not present in plugins table!'\n      vim.notify(err_message, vim.log.levels.ERROR, { title = 'packer.nvim' })\n      error(err_message)\n    end\n\n    if not plugin.loaded then\n      loader_clear_loaders(plugin)\n      if force or verify_conditions(plugin.cond, names[i]) then\n        -- Set the plugin as loaded before config is run in case something in the config tries to load\n        -- this same plugin again\n        plugin.loaded = true\n        some_unloaded = true\n        needs_bufread = needs_bufread or plugin.needs_bufread\n        loader_apply_wants(plugin, plugins)\n        cmd('packadd ' .. names[i])\n        if plugin.after_files then\n          for _, file in ipairs(plugin.after_files) do\n            cmd('silent source ' .. file)\n          end\n        end\n        loader_apply_config(plugin, names[i])\n        loader_apply_after(plugin, plugins, names[i])\n      end\n    end\n  end\n\n  if not some_unloaded then\n    return\n  end\n\n  if needs_bufread then\n    if _G._packer and _G._packer.inside_compile == true then\n      -- delaying BufRead to end of packer_compiled\n      _G._packer.needs_bufread = true\n    else\n      cmd 'doautocmd BufRead'\n    end\n  end\n  -- Retrigger cmd/keymap...\n  apply_cause_side_effects(cause)\nend\n\nlocal function load_wrapper(names, cause, plugins, force)\n  local success, err_msg = pcall(packer_load, names, cause, plugins, force)\n  if not success then\n    vim.cmd 'echohl ErrorMsg'\n    vim.cmd('echomsg \"Error in packer_compiled: ' .. vim.fn.escape(err_msg, '\"') .. '\"')\n    vim.cmd 'echomsg \"Please check your config for correctness\"'\n    vim.cmd 'echohl None'\n  end\nend\n\nreturn load_wrapper\n"
  },
  {
    "path": "lua/packer/log.lua",
    "content": "-- log.lua\n--\n-- Inspired by rxi/log.lua\n-- Modified by tjdevries and can be found at github.com/tjdevries/vlog.nvim\n--\n-- This library is free software; you can redistribute it and/or modify it\n-- under the terms of the MIT license. See LICENSE for details.\n-- User configuration section\nlocal default_config = {\n  -- Name of the plugin. Prepended to log messages\n  plugin = 'packer.nvim',\n\n  -- Should print the output to neovim while running\n  use_console = true,\n\n  -- Should highlighting be used in console (using echohl)\n  highlights = true,\n\n  -- Should write to a file\n  use_file = true,\n\n  -- Any messages above this level will be logged.\n  level = 'debug',\n\n  -- Level configuration\n  modes = {\n    { name = 'trace', hl = 'Comment' },\n    { name = 'debug', hl = 'Comment' },\n    { name = 'info', hl = 'None' },\n    { name = 'warn', hl = 'WarningMsg' },\n    { name = 'error', hl = 'ErrorMsg' },\n    { name = 'fatal', hl = 'ErrorMsg' },\n  },\n\n  -- Which levels should be logged?\n  active_levels = { [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true },\n\n  -- Can limit the number of decimals displayed for floats\n  float_precision = 0.01,\n}\n\n-- {{{ NO NEED TO CHANGE\nlocal log = {}\n\nlocal unpack = unpack or table.unpack\n\nlocal level_ids = { trace = 1, debug = 2, info = 3, warn = 4, error = 5, fatal = 6 }\nlog.cfg = function(_config)\n  local min_active_level = level_ids[_config.log.level]\n  local config = { active_levels = {} }\n  if min_active_level then\n    for i = min_active_level, 6 do\n      config.active_levels[i] = true\n    end\n  end\n  log.new(config, true)\nend\n\nlog.new = function(config, standalone)\n  config = vim.tbl_deep_extend('force', default_config, config)\n  local outfile = string.format('%s/%s.log', vim.fn.stdpath 'cache', config.plugin)\n  vim.fn.mkdir(vim.fn.stdpath 'cache', 'p')\n  local obj\n  if standalone then\n    obj = log\n  else\n    obj = {}\n  end\n\n  local levels = {}\n  for i, v in ipairs(config.modes) do\n    levels[v.name] = i\n  end\n\n  local round = function(x, increment)\n    increment = increment or 1\n    x = x / increment\n    return (x > 0 and math.floor(x + 0.5) or math.ceil(x - 0.5)) * increment\n  end\n\n  local make_string = function(...)\n    local t = {}\n    for i = 1, select('#', ...) do\n      local x = select(i, ...)\n\n      if type(x) == 'number' and config.float_precision then\n        x = tostring(round(x, config.float_precision))\n      elseif type(x) == 'table' then\n        x = vim.inspect(x)\n      else\n        x = tostring(x)\n      end\n\n      t[#t + 1] = x\n    end\n    return table.concat(t, ' ')\n  end\n\n  local console_output = vim.schedule_wrap(function(level_config, info, nameupper, msg)\n    local console_lineinfo = vim.fn.fnamemodify(info.short_src, ':t') .. ':' .. info.currentline\n    local console_string = string.format('[%-6s%s] %s: %s', nameupper, os.date '%H:%M:%S', console_lineinfo, msg)\n    -- Heuristic to check for nvim-notify\n    local is_fancy_notify = type(vim.notify) == 'table'\n    vim.notify(\n      string.format([[%s%s]], is_fancy_notify and '' or ('[' .. config.plugin .. '] '), console_string),\n      vim.log.levels[level_config.name:upper()],\n      { title = config.plugin }\n    )\n  end)\n\n  local log_at_level = function(level, level_config, message_maker, ...)\n    -- Return early if we're below the config.level\n    if level < levels[config.level] then\n      return\n    end\n    local nameupper = level_config.name:upper()\n\n    local msg = message_maker(...)\n    local info = debug.getinfo(2, 'Sl')\n    local lineinfo = info.short_src .. ':' .. info.currentline\n\n    -- Output to console\n    if config.use_console and config.active_levels[level] then\n      console_output(level_config, info, nameupper, msg)\n    end\n\n    -- Output to log file\n    if config.use_file and config.active_levels[level] then\n      local fp, err = io.open(outfile, 'a')\n      if not fp then\n        print(err)\n        return\n      end\n\n      local str = string.format('[%-6s%s %s] %s: %s\\n', nameupper, os.date(), vim.loop.hrtime(), lineinfo, msg)\n      fp:write(str)\n      fp:close()\n    end\n  end\n\n  for i, x in ipairs(config.modes) do\n    obj[x.name] = function(...)\n      return log_at_level(i, x, make_string, ...)\n    end\n\n    obj[('fmt_%s'):format(x.name)] = function()\n      return log_at_level(i, x, function(...)\n        local passed = { ... }\n        local fmt = table.remove(passed, 1)\n        local inspected = {}\n        for _, v in ipairs(passed) do\n          table.insert(inspected, vim.inspect(v))\n        end\n        return string.format(fmt, unpack(inspected))\n      end)\n    end\n  end\nend\n\nlog.new(default_config, true)\n-- }}}\n\nreturn log\n"
  },
  {
    "path": "lua/packer/luarocks.lua",
    "content": "-- Add support for installing and cleaning Luarocks dependencies\n-- Based off of plenary/neorocks/init.lua in https://github.com/nvim-lua/plenary.nvim\nlocal a = require 'packer.async'\nlocal jobs = require 'packer.jobs'\nlocal log = require 'packer.log'\nlocal result = require 'packer.result'\nlocal util = require 'packer.util'\n\nlocal fmt = string.format\nlocal async = a.sync\nlocal await = a.wait\n\nlocal config = nil\nlocal function cfg(_config)\n  config = _config.luarocks\nend\nlocal function warn_need_luajit()\n  log.error 'LuaJIT is required for Luarocks functionality!'\nend\n\nlocal lua_version = nil\nif jit then\n  local jit_version = string.gsub(jit.version, 'LuaJIT ', '')\n  lua_version = { lua = string.gsub(_VERSION, 'Lua ', ''), jit = jit_version, dir = jit_version }\nelse\n  return {\n    handle_command = warn_need_luajit,\n    install_commands = warn_need_luajit,\n    list = warn_need_luajit,\n    install_hererocks = warn_need_luajit,\n    setup_paths = warn_need_luajit,\n    uninstall = warn_need_luajit,\n    clean = warn_need_luajit,\n    install = warn_need_luajit,\n    ensure = warn_need_luajit,\n    generate_path_setup = function()\n      return ''\n    end,\n    cfg = cfg,\n  }\nend\n\nlocal cache_path = vim.fn.stdpath 'cache'\nlocal rocks_path = util.join_paths(cache_path, 'packer_hererocks')\nlocal hererocks_file = util.join_paths(rocks_path, 'hererocks.py')\nlocal hererocks_install_dir = util.join_paths(rocks_path, lua_version.dir)\nlocal shell_hererocks_dir = vim.fn.shellescape(hererocks_install_dir)\nlocal _hererocks_setup_done = false\nlocal function hererocks_is_setup()\n  if _hererocks_setup_done then\n    return true\n  end\n  local path_info = vim.loop.fs_stat(util.join_paths(hererocks_install_dir, 'lib'))\n  _hererocks_setup_done = (path_info ~= nil) and (path_info['type'] == 'directory')\n  return _hererocks_setup_done\nend\n\nlocal function hererocks_installer(disp)\n  return async(function()\n    local hererocks_url = 'https://raw.githubusercontent.com/luarocks/hererocks/master/hererocks.py'\n    local hererocks_cmd\n    await(a.main)\n    vim.fn.mkdir(rocks_path, 'p')\n    if vim.fn.executable 'curl' > 0 then\n      hererocks_cmd = 'curl ' .. hererocks_url .. ' -o ' .. hererocks_file\n    elseif vim.fn.executable 'wget' > 0 then\n      hererocks_cmd = 'wget ' .. hererocks_url .. ' -O ' .. hererocks_file .. ' --verbose'\n    else\n      return result.err '\"curl\" or \"wget\" is required to install hererocks'\n    end\n\n    if disp ~= nil then\n      disp:task_start('luarocks-hererocks', 'installing hererocks...')\n    end\n    local output = jobs.output_table()\n    local callbacks = {\n      stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, 'luarocks-hererocks'),\n      stderr = jobs.logging_callback(output.err.stderr, output.data.stderr),\n    }\n\n    local opts = { capture_output = callbacks }\n    local r = await(jobs.run(hererocks_cmd, opts)):map_err(function(err)\n      return { msg = 'Error installing hererocks', data = err, output = output }\n    end)\n\n    local luarocks_cmd = config.python_cmd\n      .. ' '\n      .. hererocks_file\n      .. ' --verbose -j '\n      .. lua_version.jit\n      .. ' -r latest '\n      .. hererocks_install_dir\n    r:and_then(await, jobs.run(luarocks_cmd, opts))\n      :map_ok(function()\n        if disp then\n          disp:task_succeeded('luarocks-hererocks', 'installed hererocks!')\n        end\n      end)\n      :map_err(function(err)\n        if disp then\n          disp:task_failed('luarocks-hererocks', 'failed to install hererocks!')\n        end\n        log.error('Failed to install hererocks: ' .. vim.inspect(err))\n        return { msg = 'Error installing luarocks', data = err, output = output }\n      end)\n    return r\n  end)\nend\n\nlocal function package_patterns(dir)\n  local sep = util.get_separator()\n  return fmt('%s%s?.lua;%s%s?%sinit.lua', dir, sep, dir, sep, sep)\nend\n\nlocal package_paths = (function()\n  local install_path = util.join_paths(hererocks_install_dir, 'lib', 'luarocks', fmt('rocks-%s', lua_version.lua))\n  local share_path = util.join_paths(hererocks_install_dir, 'share', 'lua', lua_version.lua)\n  return package_patterns(share_path) .. ';' .. package_patterns(install_path)\nend)()\n\nlocal nvim_paths_are_setup = false\nlocal function setup_nvim_paths()\n  if not hererocks_is_setup() then\n    log.warn 'Tried to setup Neovim Lua paths before hererocks was setup!'\n    return\n  end\n\n  if nvim_paths_are_setup then\n    log.warn 'Tried to setup Neovim Lua paths redundantly!'\n    return\n  end\n\n  if not string.find(package.path, package_paths, 1, true) then\n    package.path = package.path .. ';' .. package_paths\n  end\n\n  local install_cpath = util.join_paths(hererocks_install_dir, 'lib', 'lua', lua_version.lua)\n  local install_cpath_pattern = fmt('%s%s?.so', install_cpath, util.get_separator())\n  if not string.find(package.cpath, install_cpath_pattern, 1, true) then\n    package.cpath = package.cpath .. ';' .. install_cpath_pattern\n  end\n\n  nvim_paths_are_setup = true\nend\n\nlocal function generate_path_setup_code()\n  local package_path_str = vim.inspect(package_paths)\n  local install_cpath = util.join_paths(hererocks_install_dir, 'lib', 'lua', lua_version.lua)\n  local install_cpath_pattern = fmt('\"%s%s?.so\"', install_cpath, util.get_separator())\n  install_cpath_pattern = vim.fn.escape(install_cpath_pattern, [[\\]])\n  return [[\nlocal package_path_str = ]] .. package_path_str .. [[\n\nlocal install_cpath_pattern = ]] .. install_cpath_pattern .. [[\n\nif not string.find(package.path, package_path_str, 1, true) then\n  package.path = package.path .. ';' .. package_path_str\nend\n\nif not string.find(package.cpath, install_cpath_pattern, 1, true) then\n  package.cpath = package.cpath .. ';' .. install_cpath_pattern\nend\n]]\nend\n\nlocal function activate_hererocks_cmd(install_path)\n  local activate_file = 'activate'\n  local user_shell = os.getenv 'SHELL'\n  local shell = user_shell:gmatch '([^/]*)$'()\n  if shell == 'fish' then\n    activate_file = 'activate.fish'\n  elseif shell == 'csh' then\n    activate_file = 'activate.csh'\n  end\n\n  return fmt('source %s', util.join_paths(install_path, 'bin', activate_file))\nend\n\nlocal function run_luarocks(args, disp, operation_name)\n  local cmd = {\n    os.getenv 'SHELL',\n    '-c',\n    fmt('%s && luarocks --tree=%s %s', activate_hererocks_cmd(hererocks_install_dir), shell_hererocks_dir, args),\n  }\n  return async(function()\n    local output = jobs.output_table()\n    local callbacks = {\n      stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, operation_name),\n      stderr = jobs.logging_callback(output.err.stderr, output.data.stderr),\n    }\n\n    local opts = { capture_output = callbacks }\n    return await(jobs.run(cmd, opts))\n      :map_err(function(err)\n        return { msg = fmt('Error running luarocks %s', args), data = err, output = output }\n      end)\n      :map_ok(function(data)\n        return { data = data, output = output }\n      end)\n  end)\nend\n\nlocal luarocks_keys = { only_server = 'only-server', only_source = 'only-sources' }\n\nlocal function is_valid_luarock_key(key)\n  return not (key == 'tree' or key == 'local')\nend\n\nlocal function format_luarocks_args(package)\n  if type(package) ~= 'table' then\n    return ''\n  end\n  local args = {}\n  for key, value in pairs(package) do\n    if type(key) == 'string' and is_valid_luarock_key(key) then\n      local luarock_key = luarocks_keys[key] and luarocks_keys[key] or key\n      if luarock_key and type(value) == 'string' then\n        table.insert(args, string.format('--%s=%s', key, value))\n      elseif key == 'env' and type(value) == 'table' then\n        for name, env_value in pairs(value) do\n          table.insert(args, string.format('%s=%s', name, env_value))\n        end\n      end\n    end\n  end\n  return ' ' .. table.concat(args, ' ')\nend\n\nlocal function luarocks_install(package, results, disp)\n  return async(function()\n    local package_name = type(package) == 'table' and package[1] or package\n    if disp then\n      disp:task_update('luarocks-install', 'installing ' .. package_name)\n    end\n    local args = format_luarocks_args(package)\n    local version = package.version and ' ' .. package.version .. ' ' or ''\n    local install_result = await(run_luarocks('install ' .. package_name .. version .. args, disp, 'luarocks-install'))\n    if results then\n      results.luarocks.installs[package_name] = install_result\n    end\n    return install_result\n  end)\nend\n\nlocal function install_packages(packages, results, disp)\n  return async(function()\n    local r = result.ok()\n    if not hererocks_is_setup() then\n      r:and_then(await, hererocks_installer(disp))\n    end\n    if disp then\n      disp:task_start('luarocks-install', 'installing rocks...')\n    end\n    if results then\n      results.luarocks.installs = {}\n    end\n    for _, package in ipairs(packages) do\n      r:and_then(await, luarocks_install(package, results, disp))\n    end\n    r:map_ok(function()\n      if disp then\n        disp:task_succeeded('luarocks-install', 'rocks installed!')\n      end\n    end):map_err(function()\n      if disp then\n        disp:task_failed('luarocks-install', 'installing rocks failed!')\n      end\n    end)\n    return r\n  end)\nend\n\n--- Install the packages specified with `packages` synchronously\nlocal function install_sync(packages)\n  return async(function()\n    return await(install_packages(packages))\n  end)()\nend\n\nlocal function chunk_output(output)\n  -- Merge the output to a single line, then split again. Helps to deal with inconsistent\n  -- chunking in the output collection\n  local res = table.concat(output, '\\n')\n  return vim.split(res, '\\n')\nend\n\nlocal function luarocks_list(disp)\n  return async(function()\n    local r = result.ok()\n    if not hererocks_is_setup() then\n      r:and_then(await, hererocks_installer(disp))\n    end\n    r:and_then(await, run_luarocks 'list --porcelain')\n    return r:map_ok(function(data)\n      local results = {}\n      local output = chunk_output(data.output.data.stdout)\n      for _, line in ipairs(output) do\n        for l_package, version, status, install_path in string.gmatch(line, '([^\\t]+)\\t([^\\t]+)\\t([^\\t]+)\\t([^\\t]+)') do\n          table.insert(results, {\n            name = l_package,\n            version = version,\n            status = status,\n            install_path = install_path,\n          })\n        end\n      end\n\n      return results\n    end)\n  end)\nend\n\nlocal function luarocks_show(package, disp)\n  return async(function()\n    local r = result.ok()\n    if not hererocks_is_setup() then\n      r:and_then(await, hererocks_installer(disp))\n    end\n    r:and_then(await, run_luarocks('show --porcelain ' .. package))\n    return r:map_ok(function(data)\n      local output = chunk_output(data.output.data.stdout)\n      local dependencies = {}\n      for _, line in ipairs(output) do\n        local components = {}\n        for component in string.gmatch(line, '([^%s]+)') do\n          components[#components + 1] = component\n        end\n\n        if (components[1] == 'dependency' or components[1] == 'indirect_dependency') and (components[2] ~= 'lua') then\n          dependencies[components[2]] = components[2]\n        end\n      end\n\n      return dependencies\n    end)\n  end)\nend\n\nlocal function luarocks_remove(package, results, disp)\n  return async(function()\n    if disp then\n      disp:task_update('luarocks-remove', 'removing ' .. package)\n    end\n    local remove_result = await(run_luarocks('remove ' .. package, disp, 'luarocks-remove'))\n    if results then\n      results.luarocks.removals[package] = remove_result\n    end\n    return remove_result\n  end)\nend\n\nlocal function uninstall_packages(packages, results, disp)\n  return async(function()\n    local r = result.ok()\n    if not hererocks_is_setup() then\n      r:and_then(await, hererocks_installer(disp))\n    end\n    if disp then\n      disp:task_start('luarocks-remove', 'uninstalling rocks...')\n    end\n    if results then\n      results.luarocks.removals = {}\n    end\n    for _, package in ipairs(packages) do\n      local name = type(package) == 'table' and package[1] or package\n      r:and_then(await, luarocks_remove(name, results, disp))\n    end\n    r:map_ok(function()\n      if disp then\n        disp:task_succeeded('luarocks-remove', 'rocks cleaned!')\n      end\n    end):map_err(function()\n      if disp then\n        disp:task_failed('luarocks-remove', 'cleaning rocks failed!')\n      end\n    end)\n    return r\n  end)\nend\n\n--- Uninstall the packages specified with `packages` synchronously\nlocal function uninstall_sync(packages)\n  return async(function()\n    return await(uninstall_packages(packages))\n  end)()\nend\n\nlocal function clean_rocks(rocks, results, disp)\n  return async(function()\n    local r = result.ok()\n    if not hererocks_is_setup() then\n      return r\n    end\n    r:and_then(await, luarocks_list(disp))\n    local installed_packages\n    if r.ok then\n      installed_packages = r.ok\n    else\n      return r\n    end\n\n    local dependency_info = {}\n    for _, package in ipairs(installed_packages) do\n      r:and_then(await, luarocks_show(package.name, disp))\n      if r.ok then\n        dependency_info[package.name] = r.ok\n      end\n    end\n\n    r = r:map_ok(function()\n      local to_remove = {}\n      for _, package in ipairs(installed_packages) do\n        to_remove[package.name] = package\n      end\n      for _, rock in pairs(rocks) do\n        if type(rock) == 'table' then\n          if to_remove[rock[1]] and (not rock.version or to_remove[rock[1]].version == rock.version) then\n            to_remove[rock[1]] = nil\n          end\n        else\n          to_remove[rock] = nil\n        end\n      end\n\n      for rock, dependencies in pairs(dependency_info) do\n        if rocks[rock] ~= nil then\n          for _, dependency in pairs(dependencies) do\n            to_remove[dependency] = nil\n          end\n        end\n      end\n\n      -- Toposort to ensure that we remove packages before their dependencies\n      local removal_order = {}\n      local frontier = {}\n      for rock, _ in pairs(to_remove) do\n        if next(dependency_info[rock]) == nil then\n          frontier[#frontier + 1] = rock\n          dependency_info[rock] = nil\n        end\n      end\n\n      local inverse_dependencies = {}\n      for rock, depends in pairs(dependency_info) do\n        for d, _ in pairs(depends) do\n          inverse_dependencies[d] = inverse_dependencies[d] or {}\n          inverse_dependencies[d][rock] = true\n        end\n      end\n\n      while #frontier > 0 do\n        local rock = table.remove(frontier)\n        removal_order[#removal_order + 1] = rock\n        local inv_depends = inverse_dependencies[rock]\n        if inv_depends ~= nil then\n          for depends, _ in pairs(inverse_dependencies[rock]) do\n            table.remove(dependency_info[depends])\n            if #dependency_info[depends] == 0 then\n              frontier[#frontier + 1] = depends\n            end\n          end\n        end\n      end\n\n      local reverse_order = {}\n      for i = #removal_order, 1, -1 do\n        reverse_order[#reverse_order + 1] = removal_order[i]\n      end\n      return reverse_order\n    end)\n\n    if results ~= nil then\n      results.luarocks = results.luarocks or {}\n    end\n    return r:and_then(await, uninstall_packages(r.ok, results, disp))\n  end)\nend\n\nlocal function ensure_rocks(rocks, results, disp)\n  return async(function()\n    local to_install = {}\n    for _, rock in pairs(rocks) do\n      if type(rock) == 'table' then\n        to_install[rock[1]:lower()] = rock\n      else\n        to_install[rock:lower()] = true\n      end\n    end\n\n    local r = result.ok()\n    if next(to_install) == nil then\n      return r\n    end\n    if disp == nil then\n      disp = require('packer.display').open(config.display.open_fn or config.display.open_cmd)\n    end\n    if not hererocks_is_setup() then\n      r = r:and_then(await, hererocks_installer(disp))\n    end\n    r:and_then(await, luarocks_list(disp))\n    r:map_ok(function(installed_packages)\n      for _, package in ipairs(installed_packages) do\n        local spec = to_install[package.name]\n        if spec then\n          if type(spec) == 'table' then\n            -- if the package is on the system and the spec has no version\n            -- or it has a version and that is the version on the system do not install it again\n            if not spec.version or (spec.version and spec.version == package.version) then\n              to_install[package.name] = nil\n            end\n          else\n            to_install[package.name] = nil\n          end\n        end\n      end\n\n      local package_specs = {}\n      for name, spec in pairs(to_install) do\n        if type(spec) == 'table' then\n          table.insert(package_specs, spec)\n        else\n          table.insert(package_specs, { name })\n        end\n      end\n\n      return package_specs\n    end)\n\n    results.luarocks = results.luarocks or {}\n    return r:and_then(await, install_packages(r.ok, results, disp))\n  end)\nend\n\nlocal function handle_command(cmd, ...)\n  local task\n  local packages = { ... }\n  if cmd == 'install' then\n    task = install_packages(packages)\n  elseif cmd == 'remove' then\n    task = uninstall_packages(packages)\n  else\n    log.warn 'Unrecognized command!'\n    return result.err 'Unrecognized command'\n  end\n\n  return async(function()\n    local r = await(task)\n    await(a.main)\n    local package_names = vim.fn.escape(vim.inspect(packages), '\"')\n    return r:map_ok(function(data)\n      local operation_name = cmd:sub(1, 1):upper() .. cmd:sub(2)\n      log.info(fmt('%sed packages %s', operation_name, package_names))\n      return data\n    end):map_err(function(err)\n      log.error(fmt('Failed to %s packages %s: %s', cmd, package_names, vim.fn.escape(vim.inspect(err), '\"\\n')))\n      return err\n    end)\n  end)()\nend\n\nlocal function make_commands()\n  vim.cmd [[ command! -nargs=+ PackerRocks lua require('packer.luarocks').handle_command(<f-args>) ]]\nend\n\nreturn {\n  handle_command = handle_command,\n  install_commands = make_commands,\n  list = luarocks_list,\n  install_hererocks = hererocks_installer,\n  setup_paths = setup_nvim_paths,\n  uninstall = uninstall_sync,\n  clean = clean_rocks,\n  install = install_sync,\n  ensure = ensure_rocks,\n  generate_path_setup = generate_path_setup_code,\n  cfg = cfg,\n}\n"
  },
  {
    "path": "lua/packer/plugin_types/git.lua",
    "content": "local util = require 'packer.util'\nlocal jobs = require 'packer.jobs'\nlocal a = require 'packer.async'\nlocal result = require 'packer.result'\nlocal log = require 'packer.log'\nlocal await = a.wait\nlocal async = a.sync\nlocal fmt = string.format\n\nlocal vim = vim\n\nlocal git = {}\n\nlocal blocked_env_vars = {\n  GIT_DIR = true,\n  GIT_INDEX_FILE = true,\n  GIT_OBJECT_DIRECTORY = true,\n  GIT_TERMINAL_PROMPT = true,\n  GIT_WORK_TREE = true,\n  GIT_COMMON_DIR = true,\n}\n\nlocal function ensure_git_env()\n  if git.job_env == nil then\n    local job_env = {}\n    for k, v in pairs(vim.fn.environ()) do\n      if not blocked_env_vars[k] then\n        table.insert(job_env, k .. '=' .. v)\n      end\n    end\n\n    table.insert(job_env, 'GIT_TERMINAL_PROMPT=0')\n    git.job_env = job_env\n  end\nend\n\nlocal function has_wildcard(tag)\n  if not tag then\n    return false\n  end\n  return string.match(tag, '*') ~= nil\nend\n\nlocal break_tag_pattern = [=[[bB][rR][eE][aA][kK]!?:]=]\nlocal breaking_change_pattern = [=[[bB][rR][eE][aA][kK][iI][nN][gG][ _][cC][hH][aA][nN][gG][eE]]=]\nlocal type_exclam_pattern = [=[[a-zA-Z]+!:]=]\nlocal type_scope_exclam_pattern = [=[[a-zA-Z]+%([^)]+%)!:]=]\nlocal function mark_breaking_commits(plugin, commit_bodies)\n  local commits = vim.gsplit(table.concat(commit_bodies, '\\n'), '===COMMIT_START===', true)\n  for commit in commits do\n    local commit_parts = vim.split(commit, '===BODY_START===')\n    local body = commit_parts[2]\n    local lines = vim.split(commit_parts[1], '\\n')\n    local is_breaking = (\n      body ~= nil\n      and (\n        (string.match(body, breaking_change_pattern) ~= nil)\n        or (string.match(body, break_tag_pattern) ~= nil)\n        or (string.match(body, type_exclam_pattern) ~= nil)\n        or (string.match(body, type_scope_exclam_pattern) ~= nil)\n      )\n    )\n      or (\n        lines[2] ~= nil\n        and (\n          (string.match(lines[2], breaking_change_pattern) ~= nil)\n          or (string.match(lines[2], break_tag_pattern) ~= nil)\n          or (string.match(lines[2], type_exclam_pattern) ~= nil)\n          or (string.match(lines[2], type_scope_exclam_pattern) ~= nil)\n        )\n      )\n    if is_breaking then\n      plugin.breaking_commits[#plugin.breaking_commits + 1] = lines[1]\n    end\n  end\nend\n\nlocal config = nil\ngit.cfg = function(_config)\n  config = _config.git\n  config.base_dir = _config.package_root\n  config.default_base_dir = util.join_paths(config.base_dir, _config.plugin_package)\n  config.exec_cmd = config.cmd .. ' '\n  ensure_git_env()\nend\n\n---Resets a git repo `dest` to `commit`\n---@param dest string @ path to the local git repo\n---@param commit string @ commit hash\n---@return function @ async function\nlocal function reset(dest, commit)\n  local reset_cmd = fmt(config.exec_cmd .. config.subcommands.revert_to, commit)\n  local opts = { capture_output = true, cwd = dest, options = { env = git.job_env } }\n  return async(function()\n    return await(jobs.run(reset_cmd, opts))\n  end)\nend\n\nlocal handle_checkouts = function(plugin, dest, disp, opts)\n  local plugin_name = util.get_plugin_full_name(plugin)\n  return async(function()\n    if disp ~= nil then\n      disp:task_update(plugin_name, 'fetching reference...')\n    end\n    local output = jobs.output_table()\n    local callbacks = {\n      stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, plugin_name),\n      stderr = jobs.logging_callback(output.err.stderr, output.data.stderr),\n    }\n\n    local job_opts = { capture_output = callbacks, cwd = dest, options = { env = git.job_env } }\n\n    local r = result.ok()\n\n    if plugin.tag and has_wildcard(plugin.tag) then\n      disp:task_update(plugin_name, fmt('getting tag for wildcard %s...', plugin.tag))\n      local fetch_tags = config.exec_cmd .. fmt(config.subcommands.tags_expand_fmt, plugin.tag)\n      r:and_then(await, jobs.run(fetch_tags, job_opts))\n      local data = output.data.stdout[1]\n      if data then\n        plugin.tag = vim.split(data, '\\n')[1]\n      else\n        log.warn(\n          fmt('Wildcard expansion did not found any tag for plugin %s: defaulting to latest commit...', plugin.name)\n        )\n        plugin.tag = nil -- Wildcard is not found, then we bypass the tag\n      end\n    end\n\n    if plugin.branch or (plugin.tag and not opts.preview_updates) then\n      local branch_or_tag = plugin.branch and plugin.branch or plugin.tag\n      if disp ~= nil then\n        disp:task_update(plugin_name, fmt('checking out %s %s...', plugin.branch and 'branch' or 'tag', branch_or_tag))\n      end\n      r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, branch_or_tag), job_opts))\n        :map_err(function(err)\n          return {\n            msg = fmt(\n              'Error checking out %s %s for %s',\n              plugin.branch and 'branch' or 'tag',\n              branch_or_tag,\n              plugin_name\n            ),\n            data = err,\n            output = output,\n          }\n        end)\n    end\n\n    if plugin.commit then\n      if disp ~= nil then\n        disp:task_update(plugin_name, fmt('checking out %s...', plugin.commit))\n      end\n      r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, plugin.commit), job_opts))\n        :map_err(function(err)\n          return {\n            msg = fmt('Error checking out commit %s for %s', plugin.commit, plugin_name),\n            data = err,\n            output = output,\n          }\n        end)\n    end\n\n    return r:map_ok(function(ok)\n      return { status = ok, output = output }\n    end):map_err(function(err)\n      if not err.msg then\n        return {\n          msg = fmt('Error updating %s: %s', plugin_name, table.concat(err, '\\n')),\n          data = err,\n          output = output,\n        }\n      end\n\n      err.output = output\n      return err\n    end)\n  end)\nend\n\nlocal get_rev = function(plugin)\n  local plugin_name = util.get_plugin_full_name(plugin)\n\n  local rev_cmd = config.exec_cmd .. config.subcommands.get_rev\n\n  return async(function()\n    local rev = await(jobs.run(rev_cmd, { cwd = plugin.install_path, options = { env = git.job_env }, capture_output = true }))\n      :map_ok(function(ok)\n        local _, r = next(ok.output.data.stdout)\n        return r\n      end)\n      :map_err(function(err)\n        local _, msg = fmt('%s: %s', plugin_name, next(err.output.data.stderr))\n        return msg\n      end)\n\n    return rev\n  end)\nend\n\nlocal split_messages = function(messages)\n  local lines = {}\n  for _, message in ipairs(messages) do\n    vim.list_extend(lines, vim.split(message, '\\n'))\n    table.insert(lines, '')\n  end\n  return lines\nend\n\ngit.setup = function(plugin)\n  local plugin_name = util.get_plugin_full_name(plugin)\n  local install_to = plugin.install_path\n  local install_cmd =\n    vim.split(config.exec_cmd .. fmt(config.subcommands.install, plugin.commit and 999999 or config.depth), '%s+')\n\n  local submodule_cmd = config.exec_cmd .. config.subcommands.submodules\n  local rev_cmd = config.exec_cmd .. config.subcommands.get_rev\n  local update_cmd = config.exec_cmd .. config.subcommands.update\n  local update_head_cmd = config.exec_cmd .. config.subcommands.update_head\n  local fetch_cmd = config.exec_cmd .. config.subcommands.fetch\n  if plugin.commit or plugin.tag then\n    update_cmd = fetch_cmd\n  end\n\n  local branch_cmd = config.exec_cmd .. config.subcommands.current_branch\n  local current_commit_cmd = vim.split(config.exec_cmd .. config.subcommands.get_header, '%s+')\n  for i, arg in ipairs(current_commit_cmd) do\n    current_commit_cmd[i] = string.gsub(arg, 'FMT', config.subcommands.diff_fmt)\n  end\n\n  if plugin.branch or (plugin.tag and not has_wildcard(plugin.tag)) then\n    install_cmd[#install_cmd + 1] = '--branch'\n    install_cmd[#install_cmd + 1] = plugin.branch and plugin.branch or plugin.tag\n  end\n\n  install_cmd[#install_cmd + 1] = plugin.url\n  install_cmd[#install_cmd + 1] = install_to\n\n  local needs_checkout = plugin.tag ~= nil or plugin.commit ~= nil or plugin.branch ~= nil\n\n  plugin.installer = function(disp)\n    local output = jobs.output_table()\n    local callbacks = {\n      stdout = jobs.logging_callback(output.err.stdout, output.data.stdout),\n      stderr = jobs.logging_callback(output.err.stderr, output.data.stderr, nil, disp, plugin_name),\n    }\n\n    local installer_opts = {\n      capture_output = callbacks,\n      timeout = config.clone_timeout,\n      options = { env = git.job_env },\n    }\n\n    return async(function()\n      disp:task_update(plugin_name, 'cloning...')\n      local r = await(jobs.run(install_cmd, installer_opts))\n\n      installer_opts.cwd = install_to\n      r:and_then(await, jobs.run(submodule_cmd, installer_opts))\n\n      if plugin.commit then\n        disp:task_update(plugin_name, fmt('checking out %s...', plugin.commit))\n        r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, plugin.commit), installer_opts))\n          :map_err(function(err)\n            return {\n              msg = fmt('Error checking out commit %s for %s', plugin.commit, plugin_name),\n              data = { err, output },\n            }\n          end)\n      end\n\n      r:and_then(await, jobs.run(current_commit_cmd, installer_opts))\n        :map_ok(function(_)\n          plugin.messages = output.data.stdout\n        end)\n        :map_err(function(err)\n          plugin.output = { err = output.data.stderr }\n          if not err.msg then\n            return {\n              msg = fmt('Error installing %s: %s', plugin_name, table.concat(output.data.stderr, '\\n')),\n              data = { err, output },\n            }\n          end\n        end)\n\n      return r\n    end)\n  end\n\n  plugin.remote_url = function()\n    return async(function()\n      return await(\n        jobs.run(\n          fmt('%s remote get-url origin', config.exec_cmd),\n          { capture_output = true, cwd = plugin.install_path, options = { env = git.job_env } }\n        )\n      ):map_ok(function(data)\n        return { remote = data.output.data.stdout[1] }\n      end)\n    end)\n  end\n\n  plugin.updater = function(disp, opts)\n    return async(function()\n      local update_info = { err = {}, revs = {}, output = {}, messages = {} }\n      local function exit_ok(r)\n        if #update_info.err > 0 or r.exit_code ~= 0 then\n          return result.err(r)\n        end\n        return result.ok(r)\n      end\n\n      local rev_onread = jobs.logging_callback(update_info.err, update_info.revs)\n      local rev_callbacks = { stdout = rev_onread, stderr = rev_onread }\n      disp:task_update(plugin_name, 'checking current commit...')\n      local r = await(\n        jobs.run(\n          rev_cmd,\n          { success_test = exit_ok, capture_output = rev_callbacks, cwd = install_to, options = { env = git.job_env } }\n        )\n      ):map_err(function(err)\n        plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} }\n\n        return {\n          msg = fmt('Error getting current commit for %s: %s', plugin_name, table.concat(update_info.revs, '\\n')),\n          data = err,\n        }\n      end)\n\n      local current_branch\n      disp:task_update(plugin_name, 'checking current branch...')\n      r:and_then(\n        await,\n        jobs.run(\n          branch_cmd,\n          { success_test = exit_ok, capture_output = true, cwd = install_to, options = { env = git.job_env } }\n        )\n      )\n        :map_ok(function(ok)\n          current_branch = ok.output.data.stdout[1]\n        end)\n        :map_err(function(err)\n          plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} }\n\n          return {\n            msg = fmt('Error checking current branch for %s: %s', plugin_name, table.concat(update_info.revs, '\\n')),\n            data = err,\n          }\n        end)\n\n      if not needs_checkout then\n        local origin_branch = ''\n        disp:task_update(plugin_name, 'checking origin branch...')\n        local origin_refs_path = util.join_paths(install_to, '.git', 'refs', 'remotes', 'origin', 'HEAD')\n        local origin_refs_file = vim.loop.fs_open(origin_refs_path, 'r', 438)\n        if origin_refs_file ~= nil then\n          local origin_refs_stat = vim.loop.fs_fstat(origin_refs_file)\n          -- NOTE: This should check for errors\n          local origin_refs = vim.split(vim.loop.fs_read(origin_refs_file, origin_refs_stat.size, 0), '\\n')\n          vim.loop.fs_close(origin_refs_file)\n          if #origin_refs > 0 then\n            origin_branch = string.match(origin_refs[1], [[^ref: refs/remotes/origin/(.*)]])\n          end\n        end\n\n        if current_branch ~= origin_branch then\n          needs_checkout = true\n          plugin.branch = origin_branch\n        end\n      end\n\n      local update_callbacks = {\n        stdout = jobs.logging_callback(update_info.err, update_info.output),\n        stderr = jobs.logging_callback(update_info.err, update_info.output, nil, disp, plugin_name),\n      }\n      local update_opts = {\n        success_test = exit_ok,\n        capture_output = update_callbacks,\n        cwd = install_to,\n        options = { env = git.job_env },\n      }\n\n      if needs_checkout then\n        r:and_then(await, jobs.run(config.exec_cmd .. config.subcommands.fetch, update_opts))\n        r:and_then(await, handle_checkouts(plugin, install_to, disp, opts))\n        local function merge_output(res)\n          if res.output ~= nil then\n            vim.list_extend(update_info.err, res.output.err.stderr)\n            vim.list_extend(update_info.err, res.output.err.stdout)\n            vim.list_extend(update_info.output, res.output.data.stdout)\n            vim.list_extend(update_info.output, res.output.data.stderr)\n          end\n        end\n\n        r:map_ok(merge_output)\n        r:map_err(function(err)\n          merge_output(err)\n          plugin.output = { err = vim.list_extend(update_info.err, update_info.output), data = {} }\n          local errmsg = '<unknown error>'\n          if err ~= nil and err.msg ~= nil then\n            errmsg = err.msg\n          end\n          return { msg = errmsg .. ' ' .. table.concat(update_info.output, '\\n'), data = err.data }\n        end)\n      end\n\n      if opts.preview_updates then\n        disp:task_update(plugin_name, 'fetching updates...')\n        r:and_then(await, jobs.run(fetch_cmd, update_opts))\n      elseif opts.pull_head then\n        disp:task_update(plugin_name, 'pulling updates from head...')\n        r:and_then(await, jobs.run(update_head_cmd, update_opts))\n      else\n        disp:task_update(plugin_name, 'pulling updates...')\n        r:and_then(await, jobs.run(update_cmd, update_opts)):and_then(await, jobs.run(submodule_cmd, update_opts))\n      end\n      r:map_err(function(err)\n        plugin.output = { err = vim.list_extend(update_info.err, update_info.output), data = {} }\n\n        return {\n          msg = fmt('Error getting updates for %s: %s', plugin_name, table.concat(update_info.output, '\\n')),\n          data = err,\n        }\n      end)\n\n      local post_rev_cmd\n      if plugin.tag ~= nil then\n        -- NOTE that any tag wildcard should already been expanded to a specific commit at this point\n        post_rev_cmd = string.gsub(rev_cmd, 'HEAD', string.format('%s^{}', plugin.tag))\n      elseif opts.preview_updates then\n        post_rev_cmd = string.gsub(rev_cmd, 'HEAD', 'FETCH_HEAD')\n      else\n        post_rev_cmd = rev_cmd\n      end\n      disp:task_update(plugin_name, 'checking updated commit...')\n      r:and_then(\n        await,\n        jobs.run(post_rev_cmd, {\n          success_test = exit_ok,\n          capture_output = rev_callbacks,\n          cwd = install_to,\n          options = { env = git.job_env },\n        })\n      ):map_err(function(err)\n        plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} }\n        return {\n          msg = fmt('Error checking updated commit for %s: %s', plugin_name, table.concat(update_info.revs, '\\n')),\n          data = err,\n        }\n      end)\n\n      if r.ok then\n        if update_info.revs[1] ~= update_info.revs[2] then\n          local commit_headers_onread = jobs.logging_callback(update_info.err, update_info.messages)\n          local commit_headers_callbacks = { stdout = commit_headers_onread, stderr = commit_headers_onread }\n\n          local diff_cmd = string.format(config.subcommands.diff, update_info.revs[1], update_info.revs[2])\n          local commit_headers_cmd = vim.split(config.exec_cmd .. diff_cmd, '%s+')\n          for i, arg in ipairs(commit_headers_cmd) do\n            commit_headers_cmd[i] = string.gsub(arg, 'FMT', config.subcommands.diff_fmt)\n          end\n\n          disp:task_update(plugin_name, 'getting commit messages...')\n          r:and_then(\n            await,\n            jobs.run(commit_headers_cmd, {\n              success_test = exit_ok,\n              capture_output = commit_headers_callbacks,\n              cwd = install_to,\n              options = { env = git.job_env },\n            })\n          )\n\n          plugin.output = { err = update_info.err, data = update_info.output }\n          if r.ok then\n            plugin.messages = update_info.messages\n            plugin.revs = update_info.revs\n          end\n\n          if config.mark_breaking_changes then\n            local commit_bodies = { err = {}, output = {} }\n            local commit_bodies_onread = jobs.logging_callback(commit_bodies.err, commit_bodies.output)\n            local commit_bodies_callbacks = { stdout = commit_bodies_onread, stderr = commit_bodies_onread }\n            local commit_bodies_cmd = config.exec_cmd .. config.subcommands.get_bodies\n            if opts.preview_updates then\n              commit_bodies_cmd = config.exec_cmd .. config.subcommands.get_fetch_bodies\n            end\n            disp:task_update(plugin_name, 'checking for breaking changes...')\n            r:and_then(\n              await,\n              jobs.run(commit_bodies_cmd, {\n                success_test = exit_ok,\n                capture_output = commit_bodies_callbacks,\n                cwd = install_to,\n                options = { env = git.job_env },\n              })\n            ):map_ok(function(ok)\n              plugin.breaking_commits = {}\n              mark_breaking_commits(plugin, commit_bodies.output)\n              return ok\n            end)\n          end\n        else\n          plugin.revs = update_info.revs\n          plugin.messages = update_info.messages\n        end\n      else\n        plugin.output.err = vim.list_extend(plugin.output.err, update_info.messages)\n      end\n\n      r.info = update_info\n      return r\n    end)\n  end\n\n  plugin.diff = function(commit, callback)\n    async(function()\n      local diff_cmd = config.exec_cmd .. fmt(config.subcommands.git_diff_fmt, commit)\n      local diff_info = { err = {}, output = {}, messages = {} }\n      local diff_onread = jobs.logging_callback(diff_info.err, diff_info.messages)\n      local diff_callbacks = { stdout = diff_onread, stderr = diff_onread }\n      return await(jobs.run(diff_cmd, { capture_output = diff_callbacks, cwd = install_to, options = { env = git.job_env } }))\n        :map_ok(function(_)\n          return callback(split_messages(diff_info.messages))\n        end)\n        :map_err(function(err)\n          return callback(nil, err)\n        end)\n    end)()\n  end\n\n  plugin.revert_last = function()\n    local r = result.ok()\n    async(function()\n      local revert_cmd = config.exec_cmd .. config.subcommands.revert\n      r:and_then(\n        await,\n        jobs.run(revert_cmd, { capture_output = true, cwd = install_to, options = { env = git.job_env } })\n      )\n      if needs_checkout then\n        r:and_then(await, handle_checkouts(plugin, install_to, nil, {}))\n      end\n      return r\n    end)()\n    return r\n  end\n\n  ---Reset the plugin to `commit`\n  ---@param commit string\n  plugin.revert_to = function(commit)\n    assert(type(commit) == 'string', fmt(\"commit: string expected but '%s' provided\", type(commit)))\n    return async(function()\n      require('packer.log').debug(fmt(\"Reverting '%s' to commit '%s'\", plugin.name, commit))\n      return await(reset(install_to, commit))\n    end)\n  end\n\n  ---Returns HEAD's short hash\n  ---@return string\n  plugin.get_rev = function()\n    return get_rev(plugin)\n  end\nend\n\nreturn git\n"
  },
  {
    "path": "lua/packer/plugin_types/local.lua",
    "content": "local a = require 'packer.async'\nlocal log = require 'packer.log'\nlocal util = require 'packer.util'\nlocal result = require 'packer.result'\n\nlocal async = a.sync\nlocal await = a.wait\nlocal fmt = string.format\n\nlocal config = nil\nlocal function cfg(_config)\n  config = _config\nend\n\n-- Due to #679, we know that fs_symlink requires admin privileges on Windows. This is a workaround,\n-- as suggested by @nonsleepr.\n\nlocal symlink_fn\nif util.is_windows then\n  symlink_fn = function(path, new_path, flags, callback)\n    flags = flags or {}\n    flags.junction = true\n    return vim.loop.fs_symlink(path, new_path, flags, callback)\n  end\nelse\n  symlink_fn = vim.loop.fs_symlink\nend\n\nlocal symlink = a.wrap(symlink_fn)\nlocal unlink = a.wrap(vim.loop.fs_unlink)\n\nlocal function setup_local(plugin)\n  local from = vim.loop.fs_realpath(util.strip_trailing_sep(plugin.path))\n  local to = util.strip_trailing_sep(plugin.install_path)\n\n  local plugin_name = util.get_plugin_full_name(plugin)\n  plugin.installer = function(disp)\n    return async(function()\n      disp:task_update(plugin_name, 'making symlink...')\n      local err, success = await(symlink(from, to, { dir = true }))\n      if not success then\n        plugin.output = { err = { err } }\n        return result.err(err)\n      end\n      return result.ok()\n    end)\n  end\n\n  plugin.updater = function(disp)\n    return async(function()\n      local r = result.ok()\n      disp:task_update(plugin_name, 'checking symlink...')\n      local resolved_path = vim.loop.fs_realpath(to)\n      if resolved_path ~= from then\n        disp:task_update(plugin_name, 'updating symlink...')\n        r = await(unlink(to)):and_then(symlink(from, to, { dir = true }))\n      end\n\n      return r\n    end)\n  end\n\n  plugin.revert_last = function(_)\n    log.warn \"Can't revert a local plugin!\"\n    return result.ok()\n  end\nend\n\nreturn { setup = setup_local, cfg = cfg }\n"
  },
  {
    "path": "lua/packer/plugin_types.lua",
    "content": "local config\n\nlocal function cfg(_config)\n  config = _config\nend\n\nlocal plugin_types = setmetatable({ cfg = cfg }, {\n  __index = function(self, k)\n    local v = require('packer.plugin_types.' .. k)\n    v.cfg(config)\n    self[k] = v\n    return v\n  end,\n})\n\nreturn plugin_types\n"
  },
  {
    "path": "lua/packer/plugin_utils.lua",
    "content": "local a = require 'packer.async'\nlocal jobs = require 'packer.jobs'\nlocal util = require 'packer.util'\nlocal result = require 'packer.result'\nlocal log = require 'packer.log'\n\nlocal await = a.wait\n\nlocal config = nil\nlocal plugin_utils = {}\nplugin_utils.cfg = function(_config)\n  config = _config\nend\n\nplugin_utils.custom_plugin_type = 'custom'\nplugin_utils.local_plugin_type = 'local'\nplugin_utils.git_plugin_type = 'git'\n\nplugin_utils.guess_type = function(plugin)\n  if plugin.installer then\n    plugin.type = plugin_utils.custom_plugin_type\n  elseif vim.fn.isdirectory(plugin.path) ~= 0 then\n    plugin.url = plugin.path\n    plugin.type = plugin_utils.local_plugin_type\n  elseif\n    string.sub(plugin.path, 1, 6) == 'git://'\n    or string.sub(plugin.path, 1, 6) == 'ssh://'\n    or string.sub(plugin.path, 1, 10) == 'git+ssh://'\n    or string.sub(plugin.path, 1, 10) == 'ssh+git://'\n    or string.sub(plugin.path, 1, 4) == 'http'\n    or string.match(plugin.path, '@')\n  then\n    plugin.url = plugin.path\n    plugin.type = plugin_utils.git_plugin_type\n  else\n    local path = table.concat(vim.split(plugin.path, '\\\\', true), '/')\n    plugin.url = string.format(config.git.default_url_format, path)\n    plugin.type = plugin_utils.git_plugin_type\n  end\nend\n\nplugin_utils.guess_dir_type = function(dir)\n  local globdir = vim.fn.glob(dir)\n  local dir_type = (vim.loop.fs_lstat(globdir) or { type = 'noexist' }).type\n\n  --[[ NOTE: We're assuming here that:\n             1. users only create custom plugins for non-git repos;\n             2. custom plugins don't use symlinks to install;\n             otherwise, there's no consistent way to tell from a dir alone… ]]\n  if dir_type == 'link' then\n    return plugin_utils.local_plugin_type\n  elseif vim.loop.fs_stat(globdir .. '/.git') then\n    return plugin_utils.git_plugin_type\n  elseif dir_type ~= 'noexist' then\n    return plugin_utils.custom_plugin_type\n  end\nend\n\nplugin_utils.helptags_stale = function(dir)\n  -- Adapted directly from minpac.vim\n  local txts = vim.fn.glob(util.join_paths(dir, '*.txt'), true, true)\n  vim.list_extend(txts, vim.fn.glob(util.join_paths(dir, '*.[a-z][a-z]x'), true, true))\n  local tags = vim.fn.glob(util.join_paths(dir, 'tags'), true, true)\n  vim.list_extend(tags, vim.fn.glob(util.join_paths(dir, 'tags-[a-z][a-z]'), true, true))\n  local txt_ftimes = util.map(vim.fn.getftime, txts)\n  local tag_ftimes = util.map(vim.fn.getftime, tags)\n  if #txt_ftimes == 0 then\n    return false\n  end\n  if #tag_ftimes == 0 then\n    return true\n  end\n  local txt_newest = math.max(unpack(txt_ftimes))\n  local tag_oldest = math.min(unpack(tag_ftimes))\n  return txt_newest > tag_oldest\nend\n\nplugin_utils.update_helptags = vim.schedule_wrap(function(...)\n  for _, dir in ipairs(...) do\n    local doc_dir = util.join_paths(dir, 'doc')\n    if plugin_utils.helptags_stale(doc_dir) then\n      log.info('Updating helptags for ' .. doc_dir)\n      vim.cmd('silent! helptags ' .. vim.fn.fnameescape(doc_dir))\n    end\n  end\nend)\n\nplugin_utils.update_rplugins = vim.schedule_wrap(function()\n  if vim.fn.exists ':UpdateRemotePlugins' == 2 then\n    vim.cmd [[silent UpdateRemotePlugins]]\n  end\nend)\n\nplugin_utils.ensure_dirs = function()\n  if vim.fn.isdirectory(config.opt_dir) == 0 then\n    vim.fn.mkdir(config.opt_dir, 'p')\n  end\n\n  if vim.fn.isdirectory(config.start_dir) == 0 then\n    vim.fn.mkdir(config.start_dir, 'p')\n  end\nend\n\nplugin_utils.list_installed_plugins = function()\n  local opt_plugins = {}\n  local start_plugins = {}\n  local opt_dir_handle = vim.loop.fs_opendir(config.opt_dir, nil, 50)\n  if opt_dir_handle then\n    local opt_dir_items = vim.loop.fs_readdir(opt_dir_handle)\n    while opt_dir_items do\n      for _, item in ipairs(opt_dir_items) do\n        opt_plugins[util.join_paths(config.opt_dir, item.name)] = true\n      end\n\n      opt_dir_items = vim.loop.fs_readdir(opt_dir_handle)\n    end\n  end\n\n  local start_dir_handle = vim.loop.fs_opendir(config.start_dir, nil, 50)\n  if start_dir_handle then\n    local start_dir_items = vim.loop.fs_readdir(start_dir_handle)\n    while start_dir_items do\n      for _, item in ipairs(start_dir_items) do\n        start_plugins[util.join_paths(config.start_dir, item.name)] = true\n      end\n\n      start_dir_items = vim.loop.fs_readdir(start_dir_handle)\n    end\n  end\n\n  return opt_plugins, start_plugins\nend\n\nplugin_utils.find_missing_plugins = function(plugins, opt_plugins, start_plugins)\n  return a.sync(function()\n    if opt_plugins == nil or start_plugins == nil then\n      opt_plugins, start_plugins = plugin_utils.list_installed_plugins()\n    end\n\n    -- NOTE/TODO: In the case of a plugin gaining/losing an alias, this will force a clean and\n    -- reinstall\n    local missing_plugins = {}\n    for _, plugin_name in ipairs(vim.tbl_keys(plugins)) do\n      local plugin = plugins[plugin_name]\n      if not plugin.disable then\n        local plugin_path = util.join_paths(config[plugin.opt and 'opt_dir' or 'start_dir'], plugin.short_name)\n        local plugin_installed = (plugin.opt and opt_plugins or start_plugins)[plugin_path]\n\n        await(a.main)\n        local guessed_type = plugin_utils.guess_dir_type(plugin_path)\n        if not plugin_installed or plugin.type ~= guessed_type then\n          missing_plugins[plugin_name] = true\n        elseif guessed_type == plugin_utils.git_plugin_type then\n          local r = await(plugin.remote_url())\n          local remote = r.ok and r.ok.remote or nil\n          if remote then\n            -- Form a Github-style user/repo string\n            local parts = vim.split(remote, '[:/]')\n            local repo_name = parts[#parts - 1] .. '/' .. parts[#parts]\n            repo_name = repo_name:gsub('%.git', '')\n\n            -- Also need to test for \"full URL\" plugin names, but normalized to get rid of the\n            -- protocol\n            local normalized_remote = remote:gsub('https://', ''):gsub('ssh://git@', '')\n            local normalized_plugin_name = plugin.name:gsub('https://', ''):gsub('ssh://git@', ''):gsub('\\\\', '/')\n            if (normalized_remote ~= normalized_plugin_name) and (repo_name ~= normalized_plugin_name) then\n              missing_plugins[plugin_name] = true\n            end\n          end\n        end\n      end\n    end\n\n    return missing_plugins\n  end)\nend\n\nplugin_utils.get_fs_state = function(plugins)\n  log.debug 'Updating FS state'\n  local opt_plugins, start_plugins = plugin_utils.list_installed_plugins()\n  return a.sync(function()\n    local missing_plugins = await(plugin_utils.find_missing_plugins(plugins, opt_plugins, start_plugins))\n    return { opt = opt_plugins, start = start_plugins, missing = missing_plugins }\n  end)\nend\n\nplugin_utils.load_plugin = function(plugin)\n  if plugin.opt then\n    vim.cmd('packadd ' .. plugin.short_name)\n  else\n    vim.o.runtimepath = vim.o.runtimepath .. ',' .. plugin.install_path\n    for _, pat in ipairs {\n      table.concat({ 'plugin', '**/*.vim' }, util.get_separator()),\n      table.concat({ 'after', 'plugin', '**/*.vim' }, util.get_separator()),\n    } do\n      local path = util.join_paths(plugin.install_path, pat)\n      local glob_ok, files = pcall(vim.fn.glob, path, false, true)\n      if not glob_ok then\n        if string.find(files, 'E77') then\n          vim.cmd('silent exe \"source ' .. path .. '\"')\n        else\n          error(files)\n        end\n      elseif #files > 0 then\n        for _, file in ipairs(files) do\n          file = file:gsub('\\\\', '/')\n          vim.cmd('silent exe \"source ' .. file .. '\"')\n        end\n      end\n    end\n  end\nend\n\nplugin_utils.post_update_hook = function(plugin, disp)\n  local plugin_name = util.get_plugin_full_name(plugin)\n  return a.sync(function()\n    if plugin.run or not plugin.opt then\n      await(a.main)\n      plugin_utils.load_plugin(plugin)\n    end\n\n    if plugin.run then\n      if type(plugin.run) ~= 'table' then\n        plugin.run = { plugin.run }\n      end\n      disp:task_update(plugin_name, 'running post update hooks...')\n      local hook_result = result.ok()\n      for _, task in ipairs(plugin.run) do\n        if type(task) == 'function' then\n          local success, err = pcall(task, plugin, disp)\n          if not success then\n            return result.err {\n              msg = 'Error running post update hook: ' .. vim.inspect(err),\n            }\n          end\n        elseif type(task) == 'string' then\n          if string.sub(task, 1, 1) == ':' then\n            await(a.main)\n            vim.cmd(string.sub(task, 2))\n          else\n            local hook_output = { err = {}, output = {} }\n            local hook_callbacks = {\n              stderr = jobs.logging_callback(hook_output.err, hook_output.output, nil, disp, plugin_name),\n              stdout = jobs.logging_callback(hook_output.err, hook_output.output, nil, disp, plugin_name),\n            }\n            local cmd\n            local shell = os.getenv 'SHELL' or vim.o.shell\n            if shell:find 'cmd.exe$' then\n              cmd = { shell, '/c', task }\n            else\n              cmd = { shell, '-c', task }\n            end\n            hook_result = await(jobs.run(cmd, { capture_output = hook_callbacks, cwd = plugin.install_path })):map_err(\n              function(err)\n                return {\n                  msg = string.format('Error running post update hook: %s', table.concat(hook_output.output, '\\n')),\n                  data = err,\n                }\n              end\n            )\n\n            if hook_result.err then\n              return hook_result\n            end\n          end\n        else\n          -- TODO/NOTE: This case should also capture output in case of error. The minor difficulty is\n          -- what to do if the plugin's run table (i.e. this case) already specifies output handling.\n\n          hook_result = await(jobs.run(task)):map_err(function(err)\n            return {\n              msg = string.format('Error running post update hook: %s', vim.inspect(err)),\n              data = err,\n            }\n          end)\n\n          if hook_result.err then\n            return hook_result\n          end\n        end\n      end\n\n      return hook_result\n    else\n      return result.ok()\n    end\n  end)\nend\n\nreturn plugin_utils\n"
  },
  {
    "path": "lua/packer/result.lua",
    "content": "-- A simple Result<V, E> type to simplify control flow with installers and updaters\nlocal result = {}\n\nlocal ok_result_mt = {\n  and_then = function(self, f, ...)\n    local r = f(...)\n    if r == nil then\n      return result.err('Nil result in and_then! ' .. vim.inspect(debug.traceback()))\n    end\n\n    self.ok = r.ok\n    self.err = r.err\n    setmetatable(self, getmetatable(r))\n    return self\n  end,\n  or_else = function(self)\n    return self\n  end,\n  map_ok = function(self, f)\n    self.ok = f(self.ok) or self.ok\n    return self\n  end,\n  map_err = function(self)\n    return self\n  end,\n}\n\nok_result_mt.__index = ok_result_mt\n\nlocal err_result_mt = {\n  and_then = function(self)\n    return self\n  end,\n  or_else = function(self, f, ...)\n    local r = f(...)\n    if r == nil then\n      return result.err('Nil result in or_else! ' .. vim.inspect(debug.traceback()))\n    end\n\n    self.ok = r.ok\n    self.err = r.err\n    setmetatable(self, getmetatable(r))\n    return self\n  end,\n  map_ok = function(self)\n    return self\n  end,\n  map_err = function(self, f)\n    self.err = f(self.err) or self.err\n    return self\n  end,\n}\n\nerr_result_mt.__index = err_result_mt\n\nresult.ok = function(val)\n  if val == nil then\n    val = true\n  end\n  local r = setmetatable({}, ok_result_mt)\n  r.ok = val\n  return r\nend\n\nresult.err = function(err)\n  if err == nil then\n    err = true\n  end\n  local r = setmetatable({}, err_result_mt)\n  r.err = err\n  return r\nend\n\nreturn result\n"
  },
  {
    "path": "lua/packer/snapshot.lua",
    "content": "local a = require 'packer.async'\nlocal util = require 'packer.util'\nlocal log = require 'packer.log'\nlocal plugin_utils = require 'packer.plugin_utils'\nlocal plugin_complete = require('packer').plugin_complete\nlocal result = require 'packer.result'\nlocal async = a.sync\nlocal await = a.wait\nlocal fmt = string.format\n\nlocal config = {}\n\nlocal snapshot = {\n  completion = {},\n}\n\nsnapshot.cfg = function(_config)\n  config = _config\nend\n\n--- Completion for listing snapshots in `config.snapshot_path`\n--- Intended to provide completion for PackerSnapshotDelete command\nsnapshot.completion.snapshot = function(lead, cmdline, pos)\n  local completion_list = {}\n  if config.snapshot_path == nil then\n    return completion_list\n  end\n\n  local dir = vim.loop.fs_opendir(config.snapshot_path)\n\n  if dir ~= nil then\n    local res = vim.loop.fs_readdir(dir)\n    while res ~= nil do\n      for _, entry in ipairs(res) do\n        if entry.type == 'file' and vim.startswith(entry.name, lead) then\n          completion_list[#completion_list + 1] = entry.name\n        end\n      end\n\n      res = vim.loop.fs_readdir(dir)\n    end\n  end\n\n  vim.loop.fs_closedir(dir)\n  return completion_list\nend\n\n--- Completion for listing single plugins before taking snapshot\n--- Intended to provide completion for PackerSnapshot command\nsnapshot.completion.create = function(lead, cmdline, pos)\n  local cmd_args = (vim.fn.split(cmdline, ' '))\n\n  if #cmd_args > 1 then\n    return plugin_complete(lead, cmdline, pos)\n  end\n\n  return {}\nend\n\n--- Completion for listing snapshots in `config.snapshot_path` and single plugins after\n--- the first argument is provided\n--- Intended to provide completion for PackerSnapshotRollback command\nsnapshot.completion.rollback = function(lead, cmdline, pos)\n  local cmd_args = vim.split(cmdline, ' ')\n\n  if #cmd_args > 2 then\n    return plugin_complete(lead)\n  else\n    return snapshot.completion.snapshot(lead, cmdline, pos)\n  end\nend\n\n--- Creates a with with `completed` and `failed` keys, each containing a map with plugin name as key and commit hash/error as value\n--- @param plugins list\n--- @return { ok: { failed : table<string, string>, completed : table<string, string>}}\nlocal function generate_snapshot(plugins)\n  local completed = {}\n  local failed = {}\n  local opt, start = plugin_utils.list_installed_plugins()\n  local installed = vim.tbl_extend('error', start, opt)\n\n  plugins = vim.tbl_filter(function(plugin)\n    if installed[plugin.install_path] and plugin.type == plugin_utils.git_plugin_type then -- this plugin is installed\n      return plugin\n    end\n  end, plugins)\n  return async(function()\n    for _, plugin in pairs(plugins) do\n      local rev = await(plugin.get_rev())\n\n      if rev.err then\n        failed[plugin.short_name] =\n          fmt(\"Snapshotting %s failed because of error '%s'\", plugin.short_name, vim.inspect(rev.err))\n      else\n        completed[plugin.short_name] = { commit = rev.ok }\n      end\n    end\n\n    return result.ok { failed = failed, completed = completed }\n  end)\nend\n\n---Serializes a table of git-plugins with `short_name` as table key and another\n---table with `commit`; the serialized tables will be written in the path `snapshot_path`\n---provided, if there is already a snapshot it will be overwritten\n---Snapshotting work only with `plugin_utils.git_plugin_type` type of plugins,\n---other will be ignored.\n---@param snapshot_path string realpath for snapshot file\n---@param plugins table<string, any>[]\nsnapshot.create = function(snapshot_path, plugins)\n  assert(type(snapshot_path) == 'string', fmt(\"filename needs to be a string but '%s' provided\", type(snapshot_path)))\n  assert(type(plugins) == 'table', fmt(\"plugins needs to be an array but '%s' provided\", type(plugins)))\n  return async(function()\n    local commits = await(generate_snapshot(plugins))\n\n    await(a.main)\n    local snapshot_content = vim.fn.json_encode(commits.ok.completed)\n\n    local status, res = pcall(function()\n      return vim.fn.writefile({ snapshot_content }, snapshot_path) == 0\n    end)\n\n    if status and res then\n      return result.ok {\n        message = fmt(\"Snapshot '%s' complete\", snapshot_path),\n        completed = commits.ok.completed,\n        failed = commits.ok.failed,\n      }\n    else\n      return result.err { message = fmt(\"Error on creation of snapshot '%s': '%s'\", snapshot_path, res) }\n    end\n  end)\nend\n\nlocal function fetch(plugin)\n  local git = require 'packer.plugin_types.git'\n  local opts = { capture_output = true, cwd = plugin.install_path, options = { env = git.job_env } }\n\n  return async(function()\n    return await(require('packer.jobs').run('git ' .. config.git.subcommands.fetch, opts))\n  end)\nend\n\n---Rollbacks `plugins` to the hash specified in `snapshot_path` if exists.\n---It automatically runs `git fetch --depth 999999 --progress` to retrieve the history\n---@param snapshot_path string @ realpath to the snapshot file\n---@param plugins list @ of `plugin_utils.git_plugin_type` type of plugins\n---@return {ok: {completed: table<string, string>, failed: table<string, string[]>}}\nsnapshot.rollback = function(snapshot_path, plugins)\n  assert(type(snapshot_path) == 'string', 'snapshot_path: expected string but got ' .. type(snapshot_path))\n  assert(type(plugins) == 'table', 'plugins: expected table but got ' .. type(snapshot_path))\n  log.debug('Rolling back to ' .. snapshot_path)\n  local content = vim.fn.readfile(snapshot_path)\n  ---@type string\n  local plugins_snapshot = vim.fn.json_decode(content)\n  if plugins_snapshot == nil then -- not valid snapshot file\n    return result.err(fmt(\"Couldn't load '%s' file\", snapshot_path))\n  end\n\n  local completed = {}\n  local failed = {}\n\n  return async(function()\n    for _, plugin in pairs(plugins) do\n      local function err_handler(err)\n        failed[plugin.short_name] = failed[plugin.short_name] or {}\n        failed[plugin.short_name][#failed[plugin.short_name] + 1] = err\n      end\n\n      if plugins_snapshot[plugin.short_name] then\n        local commit = plugins_snapshot[plugin.short_name].commit\n        if commit ~= nil then\n          await(fetch(plugin))\n            :map_err(err_handler)\n            :and_then(await, plugin.revert_to(commit))\n            :map_ok(function(ok)\n              completed[plugin.short_name] = ok\n            end)\n            :map_err(err_handler)\n        end\n      end\n    end\n\n    return result.ok { completed = completed, failed = failed }\n  end)\nend\n\n---Deletes the snapshot provided\n---@param snapshot_name string absolute path or just a snapshot name\nsnapshot.delete = function(snapshot_name)\n  assert(type(snapshot_name) == 'string', fmt('Expected string, got %s', type(snapshot_name)))\n  ---@type string\n  local snapshot_path = vim.loop.fs_realpath(snapshot_name)\n    or vim.loop.fs_realpath(util.join_paths(config.snapshot_path, snapshot_name))\n\n  if snapshot_path == nil then\n    local warn = fmt(\"Snapshot '%s' is wrong or doesn't exist\", snapshot_name)\n    log.warn(warn)\n    return\n  end\n\n  log.debug('Deleting ' .. snapshot_path)\n  if vim.loop.fs_unlink(snapshot_path) then\n    local info = 'Deleted ' .. snapshot_path\n    log.info(info)\n  else\n    local warn = \"Couldn't delete \" .. snapshot_path\n    log.warn(warn)\n  end\nend\n\nreturn snapshot\n"
  },
  {
    "path": "lua/packer/update.lua",
    "content": "local util = require 'packer.util'\nlocal result = require 'packer.result'\nlocal display = require 'packer.display'\nlocal a = require 'packer.async'\nlocal log = require 'packer.log'\nlocal plugin_utils = require 'packer.plugin_utils'\n\nlocal fmt = string.format\nlocal async = a.sync\nlocal await = a.wait\n\nlocal config = nil\n\nlocal function get_plugin_status(plugins, plugin_name, start_plugins, opt_plugins)\n  local status = {}\n  local plugin = plugins[plugin_name]\n  status.wrong_type = (plugin.opt and vim.tbl_contains(start_plugins, util.join_paths(config.start_dir, plugin_name)))\n    or vim.tbl_contains(opt_plugins, util.join_paths(config.opt_dir, plugin_name))\n  return status\nend\n\nlocal function cfg(_config)\n  config = _config\nend\n\nlocal function fix_plugin_type(plugin, results, fs_state)\n  local from\n  local to\n  if plugin.opt then\n    from = util.join_paths(config.start_dir, plugin.short_name)\n    to = util.join_paths(config.opt_dir, plugin.short_name)\n    fs_state.opt[to] = true\n    fs_state.start[from] = nil\n    fs_state.missing[plugin.short_name] = nil\n  else\n    from = util.join_paths(config.opt_dir, plugin.short_name)\n    to = util.join_paths(config.start_dir, plugin.short_name)\n    fs_state.start[to] = true\n    fs_state.opt[from] = nil\n    fs_state.missing[plugin.short_name] = nil\n  end\n\n  -- NOTE: If we stored all plugins somewhere off-package-path and used symlinks to put them in the\n  -- right directories, this could be lighter-weight\n  local success, msg = os.rename(from, to)\n  if not success then\n    log.error('Failed to move ' .. from .. ' to ' .. to .. ': ' .. msg)\n    results.moves[plugin.short_name] = { from = from, to = to, result = result.err(success) }\n  else\n    log.debug('Moved ' .. plugin.short_name .. ' from ' .. from .. ' to ' .. to)\n    results.moves[plugin.short_name] = { from = from, to = to, result = result.ok(success) }\n  end\nend\n\nlocal function fix_plugin_types(plugins, plugin_names, results, fs_state)\n  log.debug 'Fixing plugin types'\n  results = results or {}\n  results.moves = results.moves or {}\n  -- NOTE: This function can only be run on plugins already installed\n  for _, v in ipairs(plugin_names) do\n    local plugin = plugins[v]\n    local install_dir = util.join_paths(plugin.opt and config.start_dir or config.opt_dir, plugin.short_name)\n    if vim.loop.fs_stat(install_dir) ~= nil then\n      fix_plugin_type(plugin, results, fs_state)\n    end\n  end\n  log.debug 'Done fixing plugin types'\nend\n\nlocal function update_plugin(plugin, display_win, results, opts)\n  local plugin_name = util.get_plugin_full_name(plugin)\n  -- TODO: This will have to change when separate packages are implemented\n  local install_path = util.join_paths(config.pack_dir, plugin.opt and 'opt' or 'start', plugin.short_name)\n  plugin.install_path = install_path\n  return async(function()\n    if plugin.lock or plugin.disable then\n      return\n    end\n    display_win:task_start(plugin_name, 'updating...')\n    local r = await(plugin.updater(display_win, opts))\n    if r ~= nil and r.ok then\n      local msg = 'up to date'\n      if plugin.type == plugin_utils.git_plugin_type then\n        local info = r.info\n        local actual_update = info.revs[1] ~= info.revs[2]\n        msg = actual_update and ('updated: ' .. info.revs[1] .. '...' .. info.revs[2]) or 'already up to date'\n        if actual_update and not opts.preview_updates then\n          log.debug(fmt('Updated %s: %s', plugin_name, vim.inspect(info)))\n          r = r:and_then(await, plugin_utils.post_update_hook(plugin, display_win))\n        end\n      end\n\n      if r.ok then\n        display_win:task_succeeded(plugin_name, msg)\n      end\n    else\n      display_win:task_failed(plugin_name, 'failed to update')\n      local errmsg = '<unknown error>'\n      if r ~= nil and r.err ~= nil then\n        errmsg = r.err\n      end\n      log.debug(fmt('Failed to update %s: %s', plugin_name, vim.inspect(errmsg)))\n    end\n\n    results.updates[plugin_name] = r\n    results.plugins[plugin_name] = plugin\n  end)\nend\n\nlocal function do_update(_, plugins, update_plugins, display_win, results, opts)\n  results = results or {}\n  results.updates = results.updates or {}\n  results.plugins = results.plugins or {}\n  local tasks = {}\n  for _, v in ipairs(update_plugins) do\n    local plugin = plugins[v]\n    if plugin == nil then\n      log.error(fmt('Unknown plugin: %s', v))\n    end\n    if plugin and not plugin.frozen then\n      if display_win == nil then\n        display_win = display.open(config.display.open_fn or config.display.open_cmd)\n      end\n\n      table.insert(tasks, update_plugin(plugin, display_win, results, opts))\n    end\n  end\n\n  if #tasks == 0 then\n    log.info 'Nothing to update!'\n  end\n\n  return tasks, display_win\nend\n\nlocal update = setmetatable({ cfg = cfg }, { __call = do_update })\n\nupdate.get_plugin_status = get_plugin_status\nupdate.fix_plugin_types = fix_plugin_types\n\nreturn update\n"
  },
  {
    "path": "lua/packer/util.lua",
    "content": "local util = {}\n\nutil.map = function(func, seq)\n  local result = {}\n  for _, v in ipairs(seq) do\n    table.insert(result, func(v))\n  end\n\n  return result\nend\n\nutil.partition = function(sub, seq)\n  local sub_vals = {}\n  for _, val in ipairs(sub) do\n    sub_vals[val] = true\n  end\n\n  local result = { {}, {} }\n  for _, val in ipairs(seq) do\n    if sub_vals[val] then\n      table.insert(result[1], val)\n    else\n      table.insert(result[2], val)\n    end\n  end\n\n  return unpack(result)\nend\n\nutil.nonempty_or = function(opt, alt)\n  if #opt > 0 then\n    return opt\n  else\n    return alt\n  end\nend\n\nif jit ~= nil then\n  util.is_windows = jit.os == 'Windows'\nelse\n  util.is_windows = package.config:sub(1, 1) == '\\\\'\nend\n\nif util.is_windows and vim.o.shellslash then\n  util.use_shellslash = true\nelse\n  util.use_shallslash = false\nend\n\nutil.get_separator = function()\n  if util.is_windows and not util.use_shellslash then\n    return '\\\\'\n  end\n  return '/'\nend\n\nutil.strip_trailing_sep = function(path)\n  local res, _ = string.gsub(path, util.get_separator() .. '$', '', 1)\n  return res\nend\n\nutil.join_paths = function(...)\n  local separator = util.get_separator()\n  return table.concat({ ... }, separator)\nend\n\nutil.get_plugin_short_name = function(plugin)\n  local path = vim.fn.expand(plugin[1])\n  local name_segments = vim.split(path, util.get_separator())\n  local segment_idx = #name_segments\n  local name = plugin.as or name_segments[segment_idx]\n  while name == '' and segment_idx > 0 do\n    name = name_segments[segment_idx]\n    segment_idx = segment_idx - 1\n  end\n  return name, path\nend\n\nutil.get_plugin_full_name = function(plugin)\n  local plugin_name = plugin.name\n  if plugin.branch and plugin.branch ~= 'master' then\n    -- NOTE: maybe have to change the seperator here too\n    plugin_name = plugin_name .. '/' .. plugin.branch\n  end\n\n  if plugin.rev then\n    plugin_name = plugin_name .. '@' .. plugin.rev\n  end\n\n  return plugin_name\nend\n\nutil.remove_ending_git_url = function(url)\n  return vim.endswith(url, '.git') and url:sub(1, -5) or url\nend\n\nutil.deep_extend = function(policy, ...)\n  local result = {}\n  local function helper(policy, k, v1, v2)\n    if type(v1) ~= 'table' or type(v2) ~= 'table' then\n      if policy == 'error' then\n        error('Key ' .. vim.inspect(k) .. ' is already present with value ' .. vim.inspect(v1))\n      elseif policy == 'force' then\n        return v2\n      else\n        return v1\n      end\n    else\n      return util.deep_extend(policy, v1, v2)\n    end\n  end\n\n  for _, t in ipairs { ... } do\n    for k, v in pairs(t) do\n      if result[k] ~= nil then\n        result[k] = helper(policy, k, result[k], v)\n      else\n        result[k] = v\n      end\n    end\n  end\n\n  return result\nend\n\n-- Credit to @crs for the original function\nutil.float = function(opts)\n  local last_win = vim.api.nvim_get_current_win()\n  local last_pos = vim.api.nvim_win_get_cursor(last_win)\n  local columns = vim.o.columns\n  local lines = vim.o.lines\n  local width = math.ceil(columns * 0.8)\n  local height = math.ceil(lines * 0.8 - 4)\n  local left = math.ceil((columns - width) * 0.5)\n  local top = math.ceil((lines - height) * 0.5 - 1)\n\n  --- TODO: this is an impromptu fix for\n  --- https://github.com/wbthomason/packer.nvim/pull/325#issuecomment-832874005\n  --- ideally we should decide if the string argument passed to display openers is\n  --- required or not\n  if type(opts) ~= 'table' then\n    opts = {}\n  end\n\n  opts = vim.tbl_deep_extend('force', {\n    relative = 'editor',\n    style = 'minimal',\n    border = 'double',\n    width = width,\n    height = height,\n    col = left,\n    row = top,\n  }, opts or {})\n\n  local buf = vim.api.nvim_create_buf(false, true)\n  local win = vim.api.nvim_open_win(buf, true, opts)\n\n  function _G.__packer_restore_cursor()\n    vim.api.nvim_set_current_win(last_win)\n    vim.api.nvim_win_set_cursor(last_win, last_pos)\n  end\n\n  vim.cmd 'autocmd! BufWipeout <buffer> lua __packer_restore_cursor()'\n\n  return true, win, buf\nend\n\nreturn util\n"
  },
  {
    "path": "lua/packer.lua",
    "content": "-- TODO: Performance analysis/tuning\n-- TODO: Merge start plugins?\nlocal util = require 'packer.util'\n\nlocal join_paths = util.join_paths\nlocal stdpath = vim.fn.stdpath\n\n-- Config\nlocal packer = {}\nlocal config_defaults = {\n  ensure_dependencies = true,\n  snapshot = nil,\n  snapshot_path = join_paths(stdpath 'cache', 'packer.nvim'),\n  package_root = join_paths(stdpath 'data', 'site', 'pack'),\n  compile_path = join_paths(stdpath 'config', 'plugin', 'packer_compiled.lua'),\n  plugin_package = 'packer',\n  max_jobs = nil,\n  auto_clean = true,\n  compile_on_sync = true,\n  disable_commands = false,\n  opt_default = false,\n  transitive_opt = true,\n  transitive_disable = true,\n  auto_reload_compiled = true,\n  preview_updates = false,\n  git = {\n    mark_breaking_changes = true,\n    cmd = 'git',\n    subcommands = {\n      update = 'pull --ff-only --progress --rebase=false --force',\n      update_head = 'merge FETCH_HEAD',\n      install = 'clone --depth %i --no-single-branch --progress',\n      fetch = 'fetch --depth 999999 --progress --force',\n      checkout = 'checkout %s --',\n      update_branch = 'merge --ff-only @{u}',\n      current_branch = 'rev-parse --abbrev-ref HEAD',\n      diff = 'log --color=never --pretty=format:FMT --no-show-signature %s...%s',\n      diff_fmt = '%%h %%s (%%cr)',\n      git_diff_fmt = 'show --no-color --pretty=medium %s',\n      get_rev = 'rev-parse --short HEAD',\n      get_header = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1',\n      get_bodies = 'log --color=never --pretty=format:\"===COMMIT_START===%h%n%s===BODY_START===%b\" --no-show-signature HEAD@{1}...HEAD',\n      get_fetch_bodies = 'log --color=never --pretty=format:\"===COMMIT_START===%h%n%s===BODY_START===%b\" --no-show-signature HEAD...FETCH_HEAD',\n      submodules = 'submodule update --init --recursive --progress',\n      revert = 'reset --hard HEAD@{1}',\n      revert_to = 'reset --hard %s --',\n      tags_expand_fmt = 'tag -l %s --sort -version:refname',\n    },\n    depth = 1,\n    clone_timeout = 60,\n    default_url_format = 'https://github.com/%s.git',\n  },\n  display = {\n    non_interactive = false,\n    compact = false,\n    open_fn = nil,\n    open_cmd = '65vnew',\n    working_sym = '⟳',\n    error_sym = '✗',\n    done_sym = '✓',\n    removed_sym = '-',\n    moved_sym = '→',\n    item_sym = '•',\n    header_sym = '━',\n    header_lines = 2,\n    title = 'packer.nvim',\n    show_all_info = true,\n    prompt_border = 'double',\n    keybindings = {\n      quit = 'q',\n      toggle_update = 'u',\n      continue = 'c',\n      toggle_info = '<CR>',\n      diff = 'd',\n      prompt_revert = 'r',\n      retry = 'R',\n    },\n  },\n  luarocks = { python_cmd = 'python' },\n  log = { level = 'warn' },\n  profile = { enable = false },\n  autoremove = false,\n}\n\n--- Initialize global namespace for use for callbacks and other data generated whilst packer is\n--- running\n_G._packer = _G._packer or {}\n\nlocal config = vim.tbl_extend('force', {}, config_defaults)\nlocal plugins = nil\nlocal plugin_specifications = nil\nlocal rocks = nil\n\nlocal configurable_modules = {\n  clean = false,\n  compile = false,\n  display = false,\n  handlers = false,\n  install = false,\n  plugin_types = false,\n  plugin_utils = false,\n  update = false,\n  luarocks = false,\n  log = false,\n  snapshot = false,\n}\n\nlocal function require_and_configure(module_name)\n  local fully_qualified_name = 'packer.' .. module_name\n  local module = require(fully_qualified_name)\n  if not configurable_modules[module_name] and module.cfg then\n    configurable_modules[module_name] = true\n    module.cfg(config)\n    return module\n  end\n\n  return module\nend\n\n--- Initialize packer\n-- Forwards user configuration to sub-modules, resets the set of managed plugins, and ensures that\n-- the necessary package directories exist\npacker.init = function(user_config)\n  user_config = user_config or {}\n  config = util.deep_extend('force', config, user_config)\n  packer.reset()\n  config.package_root = vim.fn.fnamemodify(config.package_root, ':p')\n  local _\n  config.package_root, _ = string.gsub(config.package_root, util.get_separator() .. '$', '', 1)\n  config.pack_dir = join_paths(config.package_root, config.plugin_package)\n  config.opt_dir = join_paths(config.pack_dir, 'opt')\n  config.start_dir = join_paths(config.pack_dir, 'start')\n\n  local plugin_utils = require_and_configure 'plugin_utils'\n  plugin_utils.ensure_dirs()\n\n  require_and_configure 'snapshot'\n\n  if not config.disable_commands then\n    packer.make_commands()\n  end\n\n  if vim.fn.mkdir(config.snapshot_path, 'p') ~= 1 then\n    require_and_configure('log').warn(\"Couldn't create \" .. config.snapshot_path)\n  end\nend\n\npacker.make_commands = function()\n  vim.cmd [[command! -nargs=+ -complete=customlist,v:lua.require'packer.snapshot'.completion.create PackerSnapshot  lua require('packer').snapshot(<f-args>)]]\n  vim.cmd [[command! -nargs=+ -complete=customlist,v:lua.require'packer.snapshot'.completion.rollback PackerSnapshotRollback  lua require('packer').rollback(<f-args>)]]\n  vim.cmd [[command! -nargs=+ -complete=customlist,v:lua.require'packer.snapshot'.completion.snapshot PackerSnapshotDelete lua require('packer.snapshot').delete(<f-args>)]]\n  vim.cmd [[command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerInstall lua require('packer').install(<f-args>)]]\n  vim.cmd [[command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerUpdate lua require('packer').update(<f-args>)]]\n  vim.cmd [[command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerSync lua require('packer').sync(<f-args>)]]\n  vim.cmd [[command! PackerClean             lua require('packer').clean()]]\n  vim.cmd [[command! -nargs=* PackerCompile  lua require('packer').compile(<q-args>)]]\n  vim.cmd [[command! PackerStatus            lua require('packer').status()]]\n  vim.cmd [[command! PackerProfile           lua require('packer').profile_output()]]\n  vim.cmd [[command! -bang -nargs=+ -complete=customlist,v:lua.require'packer'.loader_complete PackerLoad lua require('packer').loader(<f-args>, '<bang>' == '!')]]\nend\n\npacker.reset = function()\n  plugins = {}\n  plugin_specifications = {}\n  rocks = {}\nend\n\n--- Add a Luarocks package to be managed\npacker.use_rocks = function(rock)\n  if type(rock) == 'string' then\n    rock = { rock }\n  end\n  if not vim.tbl_islist(rock) and type(rock[1]) == 'string' then\n    rocks[rock[1]] = rock\n  else\n    for _, r in ipairs(rock) do\n      local rock_name = (type(r) == 'table') and r[1] or r\n      rocks[rock_name] = r\n    end\n  end\nend\n\n--- The main logic for adding a plugin (and any dependencies) to the managed set\n-- Can be invoked with (1) a single plugin spec as a string, (2) a single plugin spec table, or (3)\n-- a list of plugin specs\n-- TODO: This should be refactored into its own module and the various keys should be implemented\n-- (as much as possible) as ordinary handlers\nlocal manage = nil\nmanage = function(plugin_data)\n  local plugin_spec = plugin_data.spec\n  local spec_line = plugin_data.line\n  local spec_type = type(plugin_spec)\n  if spec_type == 'string' then\n    plugin_spec = { plugin_spec }\n  elseif spec_type == 'table' and #plugin_spec > 1 then\n    for _, spec in ipairs(plugin_spec) do\n      manage { spec = spec, line = spec_line }\n    end\n    return\n  end\n\n  local log = require_and_configure 'log'\n  if plugin_spec[1] == vim.NIL or plugin_spec[1] == nil then\n    log.warn('No plugin name provided at line ' .. spec_line .. '!')\n    return\n  end\n\n  local name, path = util.get_plugin_short_name(plugin_spec)\n\n  if name == '' then\n    log.warn('\"' .. plugin_spec[1] .. '\" is an invalid plugin name!')\n    return\n  end\n\n  if plugins[name] and not plugins[name].from_requires then\n    log.warn('Plugin \"' .. name .. '\" is used twice! (line ' .. spec_line .. ')')\n    return\n  end\n\n  if plugin_spec.as and plugins[plugin_spec.as] then\n    log.error(\n      'The alias '\n        .. plugin_spec.as\n        .. ', specified for '\n        .. path\n        .. ' at '\n        .. spec_line\n        .. ' is already used as another plugin name!'\n    )\n    return\n  end\n\n  -- Handle aliases\n  plugin_spec.short_name = name\n  plugin_spec.name = path\n  plugin_spec.path = path\n\n  -- Some config keys modify a plugin type\n  if plugin_spec.opt then\n    plugin_spec.manual_opt = true\n  elseif plugin_spec.opt == nil and config.opt_default then\n    plugin_spec.manual_opt = true\n    plugin_spec.opt = true\n  end\n\n  local compile = require_and_configure 'compile'\n  for _, key in ipairs(compile.opt_keys) do\n    if plugin_spec[key] ~= nil then\n      plugin_spec.opt = true\n      break\n    end\n  end\n\n  plugin_spec.install_path = join_paths(plugin_spec.opt and config.opt_dir or config.start_dir, plugin_spec.short_name)\n\n  local plugin_utils = require_and_configure 'plugin_utils'\n  local plugin_types = require_and_configure 'plugin_types'\n  local handlers = require_and_configure 'handlers'\n  if not plugin_spec.type then\n    plugin_utils.guess_type(plugin_spec)\n  end\n  if plugin_spec.type ~= plugin_utils.custom_plugin_type then\n    plugin_types[plugin_spec.type].setup(plugin_spec)\n  end\n  for k, v in pairs(plugin_spec) do\n    if handlers[k] then\n      handlers[k](plugins, plugin_spec, v)\n    end\n  end\n  plugins[plugin_spec.short_name] = plugin_spec\n  if plugin_spec.rocks then\n    packer.use_rocks(plugin_spec.rocks)\n  end\n\n  -- Add the git URL for displaying in PackerStatus and PackerSync.\n  plugins[plugin_spec.short_name].url = util.remove_ending_git_url(plugin_spec.url)\n\n  if plugin_spec.requires and config.ensure_dependencies then\n    -- Handle single plugins given as strings or single plugin specs given as tables\n    if\n      type(plugin_spec.requires) == 'string'\n      or (\n        type(plugin_spec.requires) == 'table'\n        and not vim.tbl_islist(plugin_spec.requires)\n        and #plugin_spec.requires == 1\n      )\n    then\n      plugin_spec.requires = { plugin_spec.requires }\n    end\n    for _, req in ipairs(plugin_spec.requires) do\n      if type(req) == 'string' then\n        req = { req }\n      end\n      local req_name_segments = vim.split(req[1], '/')\n      local req_name = req_name_segments[#req_name_segments]\n      -- this flag marks a plugin as being from a require which we use to allow\n      -- multiple requires for a plugin without triggering a duplicate warning *IF*\n      -- the plugin is from a `requires` field and the full specification has not been called yet.\n      -- @see: https://github.com/wbthomason/packer.nvim/issues/258#issuecomment-876568439\n      req.from_requires = true\n      if not plugins[req_name] then\n        if config.transitive_opt and plugin_spec.manual_opt then\n          req.opt = true\n          if type(req.after) == 'string' then\n            req.after = { req.after, plugin_spec.short_name }\n          elseif type(req.after) == 'table' then\n            local already_after = false\n            for _, name in ipairs(req.after) do\n              already_after = already_after or (name == plugin_spec.short_name)\n            end\n            if not already_after then\n              table.insert(req.after, plugin_spec.short_name)\n            end\n          elseif req.after == nil then\n            req.after = plugin_spec.short_name\n          end\n        end\n\n        if config.transitive_disable and plugin_spec.disable then\n          req.disable = true\n        end\n\n        manage { spec = req, line = spec_line }\n      end\n    end\n  end\nend\n\n--- Add a new keyword handler\npacker.set_handler = function(name, func)\n  require_and_configure('handlers')[name] = func\nend\n\n--- Add a plugin to the managed set\npacker.use = function(plugin_spec)\n  plugin_specifications[#plugin_specifications + 1] = {\n    spec = plugin_spec,\n    line = debug.getinfo(2, 'l').currentline,\n  }\nend\n\nlocal function manage_all_plugins()\n  local log = require_and_configure 'log'\n  log.debug 'Processing plugin specs'\n  if plugins == nil or next(plugins) == nil then\n    for _, spec in ipairs(plugin_specifications) do\n      manage(spec)\n    end\n  end\nend\n\npacker.__manage_all = manage_all_plugins\n\n--- Hook to fire events after packer operations\npacker.on_complete = vim.schedule_wrap(function()\n  vim.cmd [[doautocmd User PackerComplete]]\nend)\n\n--- Hook to fire events after packer compilation\npacker.on_compile_done = function()\n  local log = require_and_configure 'log'\n\n  vim.cmd [[doautocmd User PackerCompileDone]]\n  log.debug 'packer.compile: Complete'\nend\n\n--- Clean operation:\n-- Finds plugins present in the `packer` package but not in the managed set\npacker.clean = function(results)\n  local plugin_utils = require_and_configure 'plugin_utils'\n  local a = require 'packer.async'\n  local async = a.sync\n  local await = a.wait\n  local luarocks = require_and_configure 'luarocks'\n  local clean = require_and_configure 'clean'\n  require_and_configure 'display'\n\n  manage_all_plugins()\n  async(function()\n    local luarocks_clean_task = luarocks.clean(rocks, results, nil)\n    if luarocks_clean_task ~= nil then\n      await(luarocks_clean_task)\n    end\n    local fs_state = await(plugin_utils.get_fs_state(plugins))\n    await(clean(plugins, fs_state, results))\n    packer.on_complete()\n  end)()\nend\n\n--- Install operation:\n-- Takes an optional list of plugin names as an argument. If no list is given, operates on all\n-- managed plugins.\n-- Installs missing plugins, then updates helptags and rplugins\npacker.install = function(...)\n  local log = require_and_configure 'log'\n  log.debug 'packer.install: requiring modules'\n  local plugin_utils = require_and_configure 'plugin_utils'\n  local a = require 'packer.async'\n  local async = a.sync\n  local await = a.wait\n  local luarocks = require_and_configure 'luarocks'\n  local clean = require_and_configure 'clean'\n  local install = require_and_configure 'install'\n  local display = require_and_configure 'display'\n\n  manage_all_plugins()\n  local install_plugins\n  if ... then\n    install_plugins = { ... }\n  end\n  async(function()\n    local fs_state = await(plugin_utils.get_fs_state(plugins))\n    if not install_plugins then\n      install_plugins = vim.tbl_keys(fs_state.missing)\n    end\n    if #install_plugins == 0 then\n      log.info 'All configured plugins are installed'\n      packer.on_complete()\n      return\n    end\n\n    await(a.main)\n    local start_time = vim.fn.reltime()\n    local results = {}\n    await(clean(plugins, fs_state, results))\n    await(a.main)\n    log.debug 'Gathering install tasks'\n    local tasks, display_win = install(plugins, install_plugins, results)\n    if next(tasks) then\n      log.debug 'Gathering Luarocks tasks'\n      local luarocks_ensure_task = luarocks.ensure(rocks, results, display_win)\n      if luarocks_ensure_task ~= nil then\n        table.insert(tasks, luarocks_ensure_task)\n      end\n      table.insert(tasks, 1, function()\n        return not display.status.running\n      end)\n      table.insert(tasks, 1, config.max_jobs and config.max_jobs or (#tasks - 1))\n      log.debug 'Running tasks'\n      display_win:update_headline_message(#tasks - 2 .. ' / ' .. #tasks - 2 .. ' install tasks')\n      a.interruptible_wait_pool(unpack(tasks))\n      local install_paths = {}\n      for plugin_name, r in pairs(results.installs) do\n        if r.ok then\n          table.insert(install_paths, results.plugins[plugin_name].install_path)\n        end\n      end\n\n      await(a.main)\n      plugin_utils.update_helptags(install_paths)\n      plugin_utils.update_rplugins()\n      local delta = string.gsub(vim.fn.reltimestr(vim.fn.reltime(start_time)), ' ', '')\n      display_win:final_results(results, delta)\n      packer.on_complete()\n    else\n      log.info 'Nothing to install!'\n      packer.on_complete()\n    end\n  end)()\nend\n\n-- Filter out options specified as the first argument to update or sync\n-- returns the options table and the plugin names\nlocal filter_opts_from_plugins = function(...)\n  local args = { ... }\n  local opts = {}\n  if not vim.tbl_isempty(args) then\n    local first = args[1]\n    if type(first) == 'table' then\n      table.remove(args, 1)\n      opts = first\n    elseif first == '--preview' then\n      table.remove(args, 1)\n      opts = { preview_updates = true }\n    end\n  end\n  if opts.preview_updates == nil and config.preview_updates then\n    opts.preview_updates = true\n  end\n  return opts, util.nonempty_or(args, vim.tbl_keys(plugins))\nend\n\n--- Update operation:\n-- Takes an optional list of plugin names as an argument. If no list is given, operates on all\n-- managed plugins.\n-- Fixes plugin types, installs missing plugins, then updates installed plugins and updates helptags\n-- and rplugins\n-- Options can be specified in the first argument as either a table or explicit `'--preview'`.\npacker.update = function(...)\n  local log = require_and_configure 'log'\n  log.debug 'packer.update: requiring modules'\n  local plugin_utils = require_and_configure 'plugin_utils'\n  local a = require 'packer.async'\n  local async = a.sync\n  local await = a.wait\n  local luarocks = require_and_configure 'luarocks'\n  local clean = require_and_configure 'clean'\n  local install = require_and_configure 'install'\n  local display = require_and_configure 'display'\n  local update = require_and_configure 'update'\n\n  manage_all_plugins()\n\n  local opts, update_plugins = filter_opts_from_plugins(...)\n  async(function()\n    local start_time = vim.fn.reltime()\n    local results = {}\n    local fs_state = await(plugin_utils.get_fs_state(plugins))\n    local missing_plugins, installed_plugins = util.partition(vim.tbl_keys(fs_state.missing), update_plugins)\n    update.fix_plugin_types(plugins, missing_plugins, results, fs_state)\n    await(clean(plugins, fs_state, results))\n    local _\n    _, missing_plugins = util.partition(vim.tbl_keys(results.moves), missing_plugins)\n    log.debug 'Gathering install tasks'\n    await(a.main)\n    local tasks, display_win = install(plugins, missing_plugins, results)\n    local update_tasks\n    log.debug 'Gathering update tasks'\n    await(a.main)\n    update_tasks, display_win = update(plugins, installed_plugins, display_win, results, opts)\n    vim.list_extend(tasks, update_tasks)\n    log.debug 'Gathering luarocks tasks'\n    local luarocks_ensure_task = luarocks.ensure(rocks, results, display_win)\n    if luarocks_ensure_task ~= nil then\n      table.insert(tasks, luarocks_ensure_task)\n    end\n\n    if #tasks == 0 then\n      return\n    end\n\n    table.insert(tasks, 1, function()\n      return not display.status.running\n    end)\n    table.insert(tasks, 1, config.max_jobs and config.max_jobs or (#tasks - 1))\n    display_win:update_headline_message(#tasks - 2 .. ' / ' .. #tasks - 2 .. ' update tasks')\n    log.debug 'Running tasks'\n    a.interruptible_wait_pool(unpack(tasks))\n    local install_paths = {}\n    for plugin_name, r in pairs(results.installs) do\n      if r.ok then\n        table.insert(install_paths, results.plugins[plugin_name].install_path)\n      end\n    end\n\n    for plugin_name, r in pairs(results.updates) do\n      if r.ok then\n        table.insert(install_paths, results.plugins[plugin_name].install_path)\n      end\n    end\n\n    await(a.main)\n    plugin_utils.update_helptags(install_paths)\n    plugin_utils.update_rplugins()\n    local delta = string.gsub(vim.fn.reltimestr(vim.fn.reltime(start_time)), ' ', '')\n    display_win:final_results(results, delta, opts)\n    packer.on_complete()\n  end)()\nend\n\n--- Sync operation:\n-- Takes an optional list of plugin names as an argument. If no list is given, operates on all\n-- managed plugins.\n-- Runs (in sequence):\n--  - Update plugin types\n--  - Clean stale plugins\n--  - Install missing plugins and update installed plugins\n--  - Update helptags and rplugins\npacker.sync = function(...)\n  local log = require_and_configure 'log'\n  log.debug 'packer.sync: requiring modules'\n  local plugin_utils = require_and_configure 'plugin_utils'\n  local a = require 'packer.async'\n  local async = a.sync\n  local await = a.wait\n  local luarocks = require_and_configure 'luarocks'\n  local clean = require_and_configure 'clean'\n  local install = require_and_configure 'install'\n  local display = require_and_configure 'display'\n  local update = require_and_configure 'update'\n\n  manage_all_plugins()\n\n  local opts, sync_plugins = filter_opts_from_plugins(...)\n  async(function()\n    local start_time = vim.fn.reltime()\n    local results = {}\n    local fs_state = await(plugin_utils.get_fs_state(plugins))\n    local missing_plugins, installed_plugins = util.partition(vim.tbl_keys(fs_state.missing), sync_plugins)\n\n    await(a.main)\n    update.fix_plugin_types(plugins, missing_plugins, results, fs_state)\n    local _\n    _, missing_plugins = util.partition(vim.tbl_keys(results.moves), missing_plugins)\n    if config.auto_clean then\n      await(clean(plugins, fs_state, results))\n      _, installed_plugins = util.partition(vim.tbl_keys(results.removals), installed_plugins)\n    end\n\n    await(a.main)\n    log.debug 'Gathering install tasks'\n    local tasks, display_win = install(plugins, missing_plugins, results)\n    local update_tasks\n    log.debug 'Gathering update tasks'\n    await(a.main)\n    update_tasks, display_win = update(plugins, installed_plugins, display_win, results, opts)\n    vim.list_extend(tasks, update_tasks)\n    log.debug 'Gathering luarocks tasks'\n    local luarocks_clean_task = luarocks.clean(rocks, results, display_win)\n    if luarocks_clean_task ~= nil then\n      table.insert(tasks, luarocks_clean_task)\n    end\n\n    local luarocks_ensure_task = luarocks.ensure(rocks, results, display_win)\n    if luarocks_ensure_task ~= nil then\n      table.insert(tasks, luarocks_ensure_task)\n    end\n    if #tasks == 0 then\n      return\n    end\n\n    table.insert(tasks, 1, function()\n      return not display.status.running\n    end)\n    table.insert(tasks, 1, config.max_jobs and config.max_jobs or (#tasks - 1))\n    log.debug 'Running tasks'\n    display_win:update_headline_message(#tasks - 2 .. ' / ' .. #tasks - 2 .. ' sync tasks')\n    a.interruptible_wait_pool(unpack(tasks))\n    local install_paths = {}\n    for plugin_name, r in pairs(results.installs) do\n      if r.ok then\n        table.insert(install_paths, results.plugins[plugin_name].install_path)\n      end\n    end\n\n    for plugin_name, r in pairs(results.updates) do\n      if r.ok then\n        table.insert(install_paths, results.plugins[plugin_name].install_path)\n      end\n    end\n\n    await(a.main)\n    if config.compile_on_sync then\n      packer.compile(nil, false)\n    end\n    plugin_utils.update_helptags(install_paths)\n    plugin_utils.update_rplugins()\n    local delta = string.gsub(vim.fn.reltimestr(vim.fn.reltime(start_time)), ' ', '')\n    display_win:final_results(results, delta, opts)\n    packer.on_complete()\n  end)()\nend\n\npacker.status = function()\n  local async = require('packer.async').sync\n  local display = require_and_configure 'display'\n  local log = require_and_configure 'log'\n  manage_all_plugins()\n  async(function()\n    local display_win = display.open(config.display.open_fn or config.display.open_cmd)\n    if _G.packer_plugins ~= nil then\n      display_win:status(_G.packer_plugins)\n    else\n      log.warn 'packer_plugins table is nil! Cannot run packer.status()!'\n    end\n  end)()\nend\n\nlocal function reload_module(name)\n  if name then\n    package.loaded[name] = nil\n    return require(name)\n  end\nend\n\n--- Search through all the loaded packages for those that\n--- return a function, then cross reference them with all\n--- the plugin configs and setups and if there are any matches\n--- reload the user module.\nlocal function refresh_configs(plugs)\n  local reverse_index = {}\n  for k, v in pairs(package.loaded) do\n    if type(v) == 'function' then\n      reverse_index[v] = k\n    end\n  end\n  for _, plugin in pairs(plugs) do\n    local cfg = reload_module(reverse_index[plugin.config])\n    local setup = reload_module(reverse_index[plugin.setup])\n    if cfg then\n      plugin.config = cfg\n    end\n    if setup then\n      plugin.setup = setup\n    end\n  end\nend\n\nlocal function parse_value(value)\n  if value == 'true' then\n    return true\n  end\n  if value == 'false' then\n    return false\n  end\n  return value\nend\n\nlocal function parse_args(args)\n  local result = {}\n  if args then\n    local parts = vim.split(args, ' ')\n    for _, part in ipairs(parts) do\n      if part then\n        if part:find '=' then\n          local key, value = unpack(vim.split(part, '='))\n          result[key] = parse_value(value)\n        end\n      end\n    end\n  end\n  return result\nend\n\n--- Update the compiled lazy-loader code\n--- Takes an optional argument of a path to which to output the resulting compiled code\npacker.compile = function(raw_args, move_plugins)\n  local compile = require_and_configure 'compile'\n  local log = require_and_configure 'log'\n  local a = require 'packer.async'\n  local async = a.sync\n  local await = a.wait\n\n  manage_all_plugins()\n  async(function()\n    if move_plugins ~= false then\n      local update = require_and_configure 'update'\n      local plugin_utils = require_and_configure 'plugin_utils'\n      local fs_state = await(plugin_utils.get_fs_state(plugins))\n      await(a.main)\n      update.fix_plugin_types(plugins, vim.tbl_keys(fs_state.missing), {}, fs_state)\n    end\n    local args = parse_args(raw_args)\n    local output_path = args.output_path or config.compile_path\n    local output_lua = vim.fn.fnamemodify(output_path, ':e') == 'lua'\n    local should_profile = args.profile\n    -- the user might explicitly choose for this value to be false in which case\n    -- an or operator will not work\n    if should_profile == nil then\n      should_profile = config.profile.enable\n    end\n    refresh_configs(plugins)\n    -- NOTE: we copy the plugins table so the in memory value is not mutated during compilation\n    local compiled_loader = compile(vim.deepcopy(plugins), output_lua, should_profile)\n    output_path = vim.fn.expand(output_path, true)\n    vim.fn.mkdir(vim.fn.fnamemodify(output_path, ':h'), 'p')\n    local output_file = io.open(output_path, 'w')\n    output_file:write(compiled_loader)\n    output_file:close()\n    if config.auto_reload_compiled then\n      local configs_to_run = {}\n      if _G.packer_plugins ~= nil then\n        for plugin_name, plugin_info in pairs(_G.packer_plugins) do\n          if plugin_info.loaded and plugin_info.config and plugins[plugin_name] and plugins[plugin_name].cmd then\n            configs_to_run[plugin_name] = plugin_info.config\n          end\n        end\n      end\n\n      vim.cmd('source ' .. output_path)\n      for plugin_name, plugin_config in pairs(configs_to_run) do\n        for _, config_line in ipairs(plugin_config) do\n          local success, err = pcall(loadstring(config_line), plugin_name, _G.packer_plugins[plugin_name])\n          if not success then\n            log.error('Error running config for ' .. plugin_name .. ': ' .. vim.inspect(err))\n          end\n        end\n      end\n    end\n    log.info 'Finished compiling lazy-loaders!'\n    packer.on_compile_done()\n  end)()\nend\n\npacker.profile_output = function()\n  local async = require('packer.async').sync\n  local display = require_and_configure 'display'\n  local log = require_and_configure 'log'\n\n  manage_all_plugins()\n  if _G._packer.profile_output then\n    async(function()\n      local display_win = display.open(config.display.open_fn or config.display.open_cmd)\n      display_win:profile_output(_G._packer.profile_output)\n    end)()\n  else\n    log.warn 'You must run PackerCompile with profiling enabled first e.g. PackerCompile profile=true'\n  end\nend\n\n-- Load plugins\n-- @param plugins string String of space separated plugins names\n--                      intended for PackerLoad command\n--                or list of plugin names as independent strings\npacker.loader = function(...)\n  local plugin_names = { ... }\n  local force = plugin_names[#plugin_names] == true\n  if type(plugin_names[#plugin_names]) == 'boolean' then\n    plugin_names[#plugin_names] = nil\n  end\n\n  -- We make a new table here because it's more convenient than expanding a space-separated string\n  -- into the existing plugin_names\n  local plugin_list = {}\n  for _, plugin_name in ipairs(plugin_names) do\n    vim.list_extend(\n      plugin_list,\n      vim.tbl_filter(function(name)\n        return #name > 0\n      end, vim.split(plugin_name, ' '))\n    )\n  end\n\n  require 'packer.load'(plugin_list, {}, _G.packer_plugins, force)\nend\n\n-- Completion for not yet loaded plugins\n-- Intended to provide completion for PackerLoad command\npacker.loader_complete = function(lead, _, _)\n  local completion_list = {}\n  for name, plugin in pairs(_G.packer_plugins) do\n    if vim.startswith(name, lead) and not plugin.loaded then\n      table.insert(completion_list, name)\n    end\n  end\n  table.sort(completion_list)\n  return completion_list\nend\n\n-- Completion user plugins\n-- Intended to provide completion for PackerUpdate/Sync/Install command\npacker.plugin_complete = function(lead, _, _)\n  local completion_list = vim.tbl_filter(function(name)\n    return vim.startswith(name, lead)\n  end, vim.tbl_keys(_G.packer_plugins))\n  table.sort(completion_list)\n  return completion_list\nend\n\n---Snapshots installed plugins\n---@param snapshot_name string absolute path or just a snapshot name\npacker.snapshot = function(snapshot_name, ...)\n  local async = require('packer.async').sync\n  local await = require('packer.async').wait\n  local snapshot = require 'packer.snapshot'\n  local log = require_and_configure 'log'\n  local args = { ... }\n  snapshot_name = snapshot_name or require('os').date '%Y-%m-%d'\n  local snapshot_path = vim.fn.expand(snapshot_name)\n\n  local fmt = string.format\n  log.debug(fmt('Taking snapshots of currently installed plugins to %s...', snapshot_name))\n  if vim.fn.fnamemodify(snapshot_name, ':p') ~= snapshot_path then -- is not absolute path\n    if config.snapshot_path == nil then\n      log.warn 'config.snapshot_path is not set'\n      return\n    else\n      snapshot_path = util.join_paths(config.snapshot_path, snapshot_path) -- set to default path\n    end\n  end\n\n  manage_all_plugins()\n\n  local target_plugins = plugins\n  if next(args) ~= nil then -- provided extra args\n    target_plugins = vim.tbl_filter( -- filter plugins\n      function(plugin)\n        for k, plugin_shortname in pairs(args) do\n          if plugin_shortname == plugin.short_name then\n            args[k] = nil\n            return true\n          end\n        end\n        return false\n      end,\n      plugins\n    )\n  end\n\n  local write_snapshot = true\n\n  if vim.fn.filereadable(snapshot_path) == 1 then\n    vim.ui.select(\n      { 'Replace', 'Cancel' },\n      { prompt = fmt(\"Do you want to replace '%s'?\", snapshot_path) },\n      function(_, idx)\n        write_snapshot = idx == 1\n      end\n    )\n  end\n\n  async(function()\n    if write_snapshot then\n      await(snapshot.create(snapshot_path, target_plugins))\n        :map_ok(function(ok)\n          log.info(ok.message)\n          if next(ok.failed) then\n            log.warn(\"Couldn't snapshot \" .. vim.inspect(ok.failed))\n          end\n        end)\n        :map_err(function(err)\n          log.warn(err.message)\n        end)\n    end\n  end)()\nend\n\n---Instantly rolls back plugins to a previous state specified by `snapshot_name`\n---If `snapshot_name` doesn't exist an error will be displayed\n---@param snapshot_name string @name of the snapshot or the absolute path to the snapshot\n---@vararg string @ if provided, the only plugins to be rolled back,\n---otherwise all the plugins will be rolled back\npacker.rollback = function(snapshot_name, ...)\n  local args = { ... }\n  local a = require 'packer.async'\n  local async = a.sync\n  local await = a.wait\n  local wait_all = a.wait_all\n  local snapshot = require 'packer.snapshot'\n  local log = require_and_configure 'log'\n  local fmt = string.format\n\n  async(function()\n    manage_all_plugins()\n\n    local snapshot_path = vim.loop.fs_realpath(util.join_paths(config.snapshot_path, snapshot_name))\n      or vim.loop.fs_realpath(snapshot_name)\n\n    if snapshot_path == nil then\n      local warn = fmt(\"Snapshot '%s' is wrong or doesn't exist\", snapshot_name)\n      log.warn(warn)\n      return\n    end\n\n    local target_plugins = plugins\n\n    if next(args) ~= nil then -- provided extra args\n      target_plugins = vim.tbl_filter(function(plugin)\n        for _, plugin_sname in pairs(args) do\n          if plugin_sname == plugin.short_name then\n            return true\n          end\n        end\n        return false\n      end, plugins)\n    end\n\n    await(snapshot.rollback(snapshot_path, target_plugins))\n      :map_ok(function(ok)\n        await(a.main)\n        log.info('Rollback to \"' .. snapshot_path .. '\" completed')\n        if next(ok.failed) then\n          log.warn(\"Couldn't rollback \" .. vim.inspect(ok.failed))\n        end\n      end)\n      :map_err(function(err)\n        await(a.main)\n        log.error(err)\n      end)\n\n    packer.on_complete()\n  end)()\nend\n\npacker.config = config\n\n--- Convenience function for simple setup\n-- Can be invoked as follows:\n--  spec can be a function:\n--  packer.startup(function() use 'tjdevries/colorbuddy.vim' end)\n--\n--  spec can be a table with a function as its first element and config overrides as another\n--  element:\n--  packer.startup({function() use 'tjdevries/colorbuddy.vim' end, config = { ... }})\n--\n--  spec can be a table with a table of plugin specifications as its first element, config overrides\n--  as another element, and an optional table of Luarocks rock specifications as another element:\n--  packer.startup({{'tjdevries/colorbuddy.vim'}, config = { ... }, rocks = { ... }})\npacker.startup = function(spec)\n  local log = require 'packer.log'\n  local user_func = nil\n  local user_config = nil\n  local user_plugins = nil\n  local user_rocks = nil\n  if type(spec) == 'function' then\n    user_func = spec\n  elseif type(spec) == 'table' then\n    if type(spec[1]) == 'function' then\n      user_func = spec[1]\n    elseif type(spec[1]) == 'table' then\n      user_plugins = spec[1]\n      user_rocks = spec.rocks\n    else\n      log.error 'You must provide a function or table of specifications as the first element of the argument to startup!'\n      return\n    end\n\n    -- NOTE: It might be more convenient for users to allow arbitrary config keys to be specified\n    -- and to merge them, but I feel that only avoids a single layer of nesting and adds more\n    -- complication here, so I'm not sure if the benefit justifies the cost\n    user_config = spec.config\n  end\n\n  packer.init(user_config)\n  packer.reset()\n  log = require_and_configure 'log'\n\n  if user_func then\n    setfenv(user_func, vim.tbl_extend('force', getfenv(), { use = packer.use, use_rocks = packer.use_rocks }))\n    local status, err = pcall(user_func, packer.use, packer.use_rocks)\n    if not status then\n      log.error('Failure running setup function: ' .. vim.inspect(err))\n      error(err)\n    end\n  else\n    packer.use(user_plugins)\n    if user_rocks then\n      packer.use_rocks(user_rocks)\n    end\n  end\n\n  if config.snapshot ~= nil then\n    packer.rollback(config.snapshot)\n  end\n\n  return packer\nend\n\nreturn packer\n"
  },
  {
    "path": "selene.toml",
    "content": "std=\"vim\"\n"
  },
  {
    "path": "stylua.toml",
    "content": "indent_type = \"Spaces\"\nindent_width = 2\nquote_style = \"AutoPreferSingle\"\nno_call_parentheses = true\n"
  },
  {
    "path": "tests/helpers.lua",
    "content": "local util = require 'packer.util'\n\nlocal M = { base_dir = '/tmp/__packer_tests__' }\n\n---Create a fake git repository\n---@param name string\n---@param base string\nfunction M.create_git_dir(name, base)\n  base = base or M.base_dir\n  local repo_path = util.join_paths(base, name)\n  local path = util.join_paths(repo_path, '.git')\n  if vim.fn.isdirectory(path) > 0 then\n    M.cleanup_dirs(path)\n  end\n  vim.fn.mkdir(path, 'p')\n  return repo_path\nend\n\n---Remove directories created for test purposes\n---@vararg string\nfunction M.cleanup_dirs(...)\n  for _, dir in ipairs { ... } do\n    vim.fn.delete(dir, 'rf')\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "tests/local_plugin_spec.lua",
    "content": "local a = require('plenary.async_lib.tests')\nlocal await = require('packer.async').wait\nlocal local_plugin = require('packer.plugin_types.local')\nlocal packer_path = vim.fn.stdpath('data') .. '/site/pack/packer/start/'\nlocal helpers = require('tests.helpers')\n\na.describe('Local plugin -', function()\n  a.describe('installer', function()\n    local local_plugin_path\n    local repo_name = 'test.nvim'\n    local plugin_install_path = packer_path .. repo_name\n\n    before_each(function()\n      vim.fn.mkdir(packer_path, 'p')\n      local_plugin_path = helpers.create_git_dir(repo_name)\n    end)\n\n    after_each(function() helpers.cleanup_dirs(local_plugin_path, plugin_install_path) end)\n\n    a.it('should create a symlink', function()\n      local plugin_spec = {\n        name = local_plugin_path,\n        path = local_plugin_path,\n        install_path = plugin_install_path\n      }\n\n      local_plugin.setup(plugin_spec)\n      await(plugin_spec.installer({task_update = function() end}))\n\n      assert.equal('link', vim.loop.fs_lstat(plugin_install_path).type)\n    end)\n  end)\nend)\n"
  },
  {
    "path": "tests/minimal.vim",
    "content": "set rtp+=.\nset rtp+=../plenary.nvim\nruntime! plugin/plenary.vim\n"
  },
  {
    "path": "tests/packer_plugin_utils_spec.lua",
    "content": "local a = require('plenary.async_lib.tests')\nlocal await = require('packer.async').wait\nlocal plugin_utils = require(\"packer.plugin_utils\")\nlocal packer_path = vim.fn.stdpath(\"data\") .. \"/site/pack/packer/start/\"\n\na.describe(\"Packer post update hooks\", function()\n  local test_plugin_path = packer_path .. \"test_plugin/\"\n  local run_hook = plugin_utils.post_update_hook\n\n  before_each(function() vim.fn.mkdir(test_plugin_path, \"p\") end)\n\n  after_each(function() vim.fn.delete(test_plugin_path, \"rf\") end)\n\n  a.it(\"should run the command in the correct folder\", function()\n    local plugin_spec = {\n      name = \"test/test_plugin\",\n      install_path = test_plugin_path,\n      run = \"touch 'this_file_should_exist'\"\n    }\n\n    await(run_hook(plugin_spec, {task_update = function() end}))\n\n    assert.truthy(vim.loop.fs_stat(test_plugin_path .. \"this_file_should_exist\"))\n  end)\nend)\n"
  },
  {
    "path": "tests/packer_use_spec.lua",
    "content": "local packer = require(\"packer\")\nlocal use = packer.use\nlocal packer_path = vim.fn.stdpath(\"data\")..\"/site/pack/packer/start/\"\n\ndescribe(\"Packer use tests\", function()\n  after_each(function()\n    packer.reset()\n  end)\n\n  it(\"should set the correct install path\", function ()\n    local spec = {\"test/plugin1\"}\n    packer.startup(function()\n      use(spec)\n    end)\n    packer.__manage_all()\n    assert.truthy(spec.install_path)\n    assert.equal(spec.install_path, packer_path .. spec.short_name)\n  end)\n\n  it(\"should add metadata to a plugin from a spec\", function ()\n    local spec = {\"test/plugin1\"}\n    packer.startup(function()\n      use(spec)\n    end)\n    packer.__manage_all()\n    assert.equal(spec.name, \"test/plugin1\")\n    assert.equal(spec.path, \"test/plugin1\")\n  end)\nend)\n"
  },
  {
    "path": "tests/plugin_utils_spec.lua",
    "content": "local a = require('plenary.async_lib.tests')\nlocal await = require('packer.async').wait\nlocal async = require('packer.async').sync\nlocal plugin_utils = require('packer.plugin_utils')\nlocal helpers = require(\"tests.helpers\")\n\nlocal fmt = string.format\n\na.describe('Plugin utils -', function()\n\n  a.describe('find_missing_plugins', function()\n    local repo_name = \"test.nvim\"\n    local path\n\n    plugin_utils.cfg({start_dir = helpers.base_dir})\n\n    before_each(function() path = helpers.create_git_dir(repo_name) end)\n\n    after_each(function() helpers.cleanup_dirs(\"tmp/packer\") end)\n\n    a.it('should pick up plugins with a different remote URL', function()\n      local test_repo_name = fmt('user2/%s', repo_name)\n      local plugins = {\n        [repo_name] = {\n          opt = false,\n          type = \"git\",\n          name = fmt(\"user1/%s\", repo_name),\n          short_name = repo_name,\n          remote_url = function()\n            return async(function()\n              return {ok = {remote = fmt('https://github.com/%s', test_repo_name)}}\n            end)\n          end\n        }\n      }\n      local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true}))\n      assert.truthy(result)\n      assert.equal(1, #vim.tbl_keys(result))\n    end)\n\n    a.it('should not pick up plugins with the same remote URL', function()\n      local test_repo_name = fmt('user1/%s', repo_name)\n      local plugins = {\n        [repo_name] = {\n          opt = false,\n          type = \"git\",\n          name = test_repo_name,\n          short_name = repo_name,\n          remote_url = function()\n            return async(function()\n              return {ok = {remote = fmt('https://github.com/%s', test_repo_name)}}\n            end)\n          end\n        }\n      }\n      local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true}))\n      assert.truthy(result)\n      assert.equal(0, #result)\n    end)\n\n    a.it('should handle ssh git urls', function()\n      local test_repo_name = fmt('user2/%s', repo_name)\n      local plugins = {\n        [repo_name] = {\n          opt = false,\n          type = \"git\",\n          name = fmt(\"user1/%s\", repo_name),\n          short_name = repo_name,\n          remote_url = function()\n            return async(function()\n              return {ok = {remote = fmt('git@github.com:%s.git', test_repo_name)}}\n            end)\n          end\n        }\n      }\n      local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true}))\n      assert.truthy(result)\n      assert.equal(1, #vim.tbl_keys(result))\n    end)\n  end)\nend)\n"
  },
  {
    "path": "tests/snapshot_spec.lua",
    "content": "local before_each = require('plenary.busted').before_each\nlocal a = require 'plenary.async_lib.tests'\nlocal util = require 'packer.util'\nlocal mocked_plugin_utils = require 'packer.plugin_utils'\nlocal log = require 'packer.log'\nlocal async = require('packer.async').sync\nlocal await = require('packer.async').wait\nlocal wait_all = require('packer.async').wait_all\nlocal main = require('packer.async').main\nlocal packer = require 'packer'\nlocal jobs = require 'packer.jobs'\nlocal git = require 'packer.plugin_types.git'\nlocal join_paths = util.join_paths\nlocal stdpath = vim.fn.stdpath\nlocal fmt = string.format\n\nlocal config = {\n  ensure_dependencies = true,\n  snapshot = nil,\n  snapshot_path = join_paths(stdpath 'cache', 'packer.nvim'),\n  package_root = join_paths(stdpath 'data', 'site', 'pack'),\n  compile_path = join_paths(stdpath 'config', 'plugin', 'packer_compiled.lua'),\n  plugin_package = 'packer',\n  max_jobs = nil,\n  auto_clean = true,\n  compile_on_sync = true,\n  disable_commands = false,\n  opt_default = false,\n  transitive_opt = true,\n  transitive_disable = true,\n  auto_reload_compiled = true,\n  git = {\n    mark_breaking_changes = true,\n    cmd = 'git',\n    subcommands = {\n      update = 'pull --ff-only --progress --rebase=false',\n      install = 'clone --depth %i --no-single-branch --progress',\n      fetch = 'fetch --depth 999999 --progress',\n      checkout = 'checkout %s --',\n      update_branch = 'merge --ff-only @{u}',\n      current_branch = 'rev-parse --abbrev-ref HEAD',\n      diff = 'log --color=never --pretty=format:FMT --no-show-signature HEAD@{1}...HEAD',\n      diff_fmt = '%%h %%s (%%cr)',\n      git_diff_fmt = 'show --no-color --pretty=medium %s',\n      get_rev = 'rev-parse --short HEAD',\n      get_header = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1',\n      get_bodies = 'log --color=never --pretty=format:\"===COMMIT_START===%h%n%s===BODY_START===%b\" --no-show-signature HEAD@{1}...HEAD',\n      submodules = 'submodule update --init --recursive --progress',\n      revert = 'reset --hard HEAD@{1}',\n      revert_to = 'reset --hard %s --',\n    },\n    depth = 1,\n    clone_timeout = 60,\n    default_url_format = 'https://github.com/%s.git',\n  },\n  display = {\n    non_interactive = false,\n    open_fn = nil,\n    open_cmd = '65vnew',\n    working_sym = '⟳',\n    error_sym = '✗',\n    done_sym = '✓',\n    removed_sym = '-',\n    moved_sym = '→',\n    header_sym = '━',\n    header_lines = 2,\n    title = 'packer.nvim',\n    show_all_info = true,\n    prompt_border = 'double',\n    keybindings = { quit = 'q', toggle_info = '<CR>', diff = 'd', prompt_revert = 'r' },\n  },\n  luarocks = { python_cmd = 'python' },\n  log = { level = 'trace' },\n  profile = { enable = false },\n}\n\ngit.cfg(config)\n\n--[[ For testing purposes the spec file is made up so that when running `packer`\nit could manage itself as if it was in `~/.local/share/nvim/site/pack/packer/start/` --]]\nlocal install_path = vim.fn.getcwd()\n\nmocked_plugin_utils.list_installed_plugins = function()\n  return { [install_path] = true }, {}\nend\n\nlocal old_require = _G.require\n\n_G.require = function(modname)\n  if modname == 'plugin_utils' then\n    return mocked_plugin_utils\n  end\n\n  return old_require(modname)\nend\n\nlocal spec = { 'wbthomason/packer.nvim' }\n\nlocal function exec_cmd(cmd, opts)\n  return async(function()\n    local r = await(jobs.run(cmd, opts))\n    if r.err then\n      print(fmt(\"Failed on command '%s': %s\", cmd, vim.inspect(r.err)))\n    end\n    assert.is_not_nil(r.ok)\n    local _, result = next(r.ok.output.data.stdout)\n    return result\n  end)\nend\n\nlocal snapshotted_plugins = {}\na.describe('Packer testing ', function()\n  local snapshot_name = 'test'\n  local test_path = join_paths(config.snapshot_path, snapshot_name)\n  local snapshot = require 'packer.snapshot'\n  snapshot.cfg(config)\n\n  before_each(function()\n    packer.reset()\n    packer.init(config)\n    packer.use(spec)\n    packer.__manage_all()\n  end)\n\n  after_each(function()\n    spec = { 'wbthomason/packer.nvim' }\n    spec.install_path = install_path\n  end)\n\n  a.describe('snapshot.create()', function()\n    a.it(fmt(\"create snapshot in '%s'\", test_path), function()\n      local result = await(snapshot.create(test_path, { spec }))\n      local stat = vim.loop.fs_stat(test_path)\n      assert.truthy(stat)\n    end)\n\n    a.it(\"checking if snapshot content corresponds to plugins'\", function()\n      async(function()\n        local file_content = vim.fn.readfile(test_path)\n        snapshotted_plugins = vim.fn.json_decode(file_content)\n        local expected_rev = await(spec.get_rev())\n        assert.are.equals(expected_rev.ok, snapshotted_plugins['packer.nvim'].commit)\n      end)()\n    end)\n  end)\n\n  a.describe('packer.delete()', function()\n    a.it(fmt(\"delete '%s' snapshot\", snapshot_name), function()\n      snapshot.delete(snapshot_name)\n      local stat = vim.loop.fs_stat(test_path)\n      assert.falsy(stat)\n    end)\n  end)\n\n  a.describe('packer.rollback()', function()\n    local rollback_snapshot_name = 'rollback_test'\n    local rollback_test_path = join_paths(config.snapshot_path, rollback_snapshot_name)\n    local prev_commit_cmd = 'git rev-parse --short HEAD~5'\n    local get_rev_cmd = 'git rev-parse --short HEAD'\n\n    local opts = { capture_output = true, cwd = spec.install_path, options = { env = git.job_env } }\n\n    a.it(\"restore 'packer' to the commit hash HEAD~5\", function()\n      async(function()\n        local commit = await(exec_cmd(prev_commit_cmd, opts))\n        snapshotted_plugins['packer.nvim'] = { commit = commit }\n        await(main)\n        local encoded_json = vim.fn.json_encode(snapshotted_plugins)\n        vim.fn.writefile({ encoded_json }, rollback_test_path)\n        await(snapshot.rollback(rollback_test_path, { spec }))\n        local rev = await(exec_cmd(get_rev_cmd, opts))\n        assert.are.equals(snapshotted_plugins['packer.nvim'].commit, rev)\n      end)()\n    end)\n  end)\nend)\n"
  },
  {
    "path": "vim.toml",
    "content": "[selene]\nbase = \"lua51\"\nname = \"vim\"\n\n[vim]\nany = true\n\n[jit]\nany = true\n\n[[describe.args]]\ntype = \"string\"\n[[describe.args]]\ntype = \"function\"\n\n[[it.args]]\ntype = \"string\"\n[[it.args]]\ntype = \"function\"\n\n[[before_each.args]]\ntype = \"function\"\n[[after_each.args]]\ntype = \"function\"\n\n[assert.is_not]\nany = true\n\n[[assert.equals.args]]\ntype = \"any\"\n[[assert.equals.args]]\ntype = \"any\"\n[[assert.equals.args]]\ntype = \"any\"\nrequired = false\n\n[[assert.same.args]]\ntype = \"any\"\n[[assert.same.args]]\ntype = \"any\"\n\n[[assert.truthy.args]]\ntype = \"any\"\n\n[[assert.spy.args]]\ntype = \"any\"\n\n[[assert.stub.args]]\ntype = \"any\"\n"
  }
]