[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: junegunn\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\n### Before Submitting\n\n- You checked the [faq](https://github.com/junegunn/vim-plug/wiki/faq) for common problems.\n- Check your [requirements](https://github.com/junegunn/vim-plug/wiki/requirements) are satisfied.\n- You are not going to suggest vim-plug manage itself like Vundle, see #240, #364, #367 ...\n-->\n\nExplain the problem here ...\n\n------------------------------\n\n<!-- Paste your Plug block (from `call plug#begin()` to `call plug#end()`) -->\n```\n\n```\n\n<!-- Paste the contents of `:version` below -->\n```\n\n```\n\n<!-- Check all that apply. -->\n- Type:\n    - [ ] Bug\n    - [ ] Enhancement\n    - [ ] Feature Request\n    - [ ] Question\n- OS:\n    - [ ] All/Other\n    - [ ] Linux\n    - [ ] macOS\n    - [ ] Windows\n- Vim:\n    - [ ] Terminal Vim\n    - [ ] GVim\n    - [ ] Neovim\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- ## Before Submitting\n\n- You made sure the existing tests/travis build works.\n- You made sure any new features were tested where appropriate.\n- You checked a similar feature wasn't already turned down by searching issues & PRs.\n-->\n\nDescribe the details of your PR ...\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "---\nname: Test vim-plug\n\non:\n  push:\n    branches: [master, devel]\n  pull_request:\n    branches: [master]\n  workflow_dispatch:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        vim:\n          - vim\n          # FIXME: (core dumped) https://github.com/junegunn/vim-plug/runs/4422576984?check_suite_focus=true#step:3:238\n          # - neovim-stable\n          # - neovim-unstable\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n\n      - name: Install packages and test\n        env:\n          ENV: ${{ matrix.vim }}\n        run: |\n          export DEPS=~/deps\n          export PATH=~/deps/bin:$PATH\n\n          git config --global user.email \"you@example.com\"\n          git config --global user.name \"Your Name\"\n\n          case \"$ENV\" in\n            vim)\n              sudo apt-get install vim\n              ;;\n            neovim-*)\n              sudo add-apt-repository ppa:neovim-ppa/${ENV/neovim-/}\n              sudo apt-get update\n              sudo apt-get install neovim\n\n              mkdir -p $DEPS/bin\n              echo 'nvim \"$@\"' > $DEPS/bin/vim\n              chmod +x $DEPS/bin/vim\n              export VADER_OUTPUT_FILE=/dev/stderr\n              ;;\n          esac\n\n          test/run !\n"
  },
  {
    "path": ".gitignore",
    "content": "doc/tags\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: minimal\nenv:\n  global:\n    - DEPS=$HOME/deps\n    - PATH=$DEPS/bin:$PATH\njobs:\n  include:\n    - env: ENV=vim80-bionic\n      dist: bionic\n      stage: vim8\n    - env: ENV=vim-nightly\n      dist: trusty\n      stage: vim8\n    - env: ENV=neovim-stable\n      dist: bionic\n      addons: {apt: {packages: [neovim], sources: [{sourceline: 'ppa:neovim-ppa/stable'}]}}\n      stage: neovim\n    - env: ENV=neovim-nightly\n      dist: bionic\n      addons: {apt: {packages: [neovim], sources: [{sourceline: 'ppa:neovim-ppa/unstable'}]}}\n      stage: neovim\n    - env: ENV=vim74-trusty-python\n      dist: trusty\n      stage: vim74\n    - env: ENV=vim74-xenial-python3\n      dist: xenial\n      stage: vim74\n    - env: ENV=vim74-trusty-ruby\n      dist: trusty\n      addons: {apt: {packages: [vim-nox]}}\n      stage: vim74\n    - env: ENV=vim74-xenial-ruby\n      dist: xenial\n      addons: {apt: {packages: [vim-nox]}}\n      stage: vim74\n    - env: ENV=osx-highsierra\n      os: osx\n      osx_image: xcode9.4\n      stage: vim8\ninstall: |\n  git config --global user.email \"you@example.com\"\n  git config --global user.name \"Your Name\"\n\n  C_OPTS=\"--prefix=$DEPS --with-features=huge --disable-gui \"\n  case \"$ENV\" in\n    vim-*)\n      ;;\n    neovim-*)\n      mkdir -p ${DEPS}/bin\n      ln -s /usr/bin/nvim ${DEPS}/bin/vim\n      export VADER_OUTPUT_FILE=/dev/stderr\n      return\n      ;;\n    vim74-* | vim80-*)\n      mkdir -p ${DEPS}/bin\n      ln -s /usr/bin/vim.nox ${DEPS}/bin/vim\n      return\n      ;;\n    *)\n      return\n      ;;\n  esac\n\n  git clone --depth 1 https://github.com/vim/vim\n  cd vim\n  export PATH=/usr/bin:$PATH\n  ./configure $C_OPTS\n  make\n  make install\n  cd -\nscript: test/run !\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Junegunn Choi\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": "README.md",
    "content": "<h1 title=\"vim-plug\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"./plug-dark.png\">\n    <img src=\"./plug.png\" height=\"75\" alt=\"vim-plug\">\n  </picture>\n  <a href=\"https://github.com/junegunn/vim-plug/actions/workflows/test.yml?query=branch%3Amaster\">\n    <img src=\"https://img.shields.io/github/actions/workflow/status/junegunn/vim-plug/test.yml?branch=master\">\n  </a>\n</h1>\n\nA minimalist Vim plugin manager.\n\n<img src=\"https://raw.githubusercontent.com/junegunn/i/master/vim-plug/installer.gif\" height=\"450\">\n\n## Pros.\n\n- Minimalist design\n    - Just one file with no dependencies. Super easy to set up.\n    - Concise, intuitive syntax that you can learn within minutes. No boilerplate code required.\n    - No feature bloat\n- Extremely stable with flawless backward compatibility\n    - Works perfectly with all versions of Vim since 2006 and all versions of Neovim ever released\n- [Super-fast][40/4] parallel installation/update\n- Creates shallow clones to minimize disk space usage and download time\n- On-demand loading for [faster startup time][startup-time]\n- Can review and rollback updates\n- Branch/tag/commit support\n- Post-update hooks\n- Support for externally managed plugins\n\n[40/4]: https://raw.githubusercontent.com/junegunn/i/master/vim-plug/40-in-4.gif\n[startup-time]: https://github.com/junegunn/vim-startuptime-benchmark#result\n\n## Installation\n\n[Download plug.vim](https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim)\nand put it in the \"autoload\" directory.\n\n<details>\n<summary>Click to see the instructions</summary>\n\n### Vim\n\n#### Unix\n\n```sh\ncurl -fLo ~/.vim/autoload/plug.vim --create-dirs \\\n    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim\n```\n\nYou can automate the process by putting the command in your Vim configuration\nfile as suggested [here][auto].\n\n[auto]: https://github.com/junegunn/vim-plug/wiki/tips#automatic-installation\n\n#### Windows (PowerShell)\n\n```powershell\niwr -useb https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim |`\n    ni $HOME/vimfiles/autoload/plug.vim -Force\n```\n\n### Neovim\n\n#### Unix, Linux\n\n```sh\nsh -c 'curl -fLo \"${XDG_DATA_HOME:-$HOME/.local/share}\"/nvim/site/autoload/plug.vim --create-dirs \\\n       https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'\n```\n\n#### Linux (Flatpak)\n\n```sh\ncurl -fLo ~/.var/app/io.neovim.nvim/data/nvim/site/autoload/plug.vim --create-dirs \\\n    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim\n```\n\n#### Windows (PowerShell)\n\n```powershell\niwr -useb https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim |`\n    ni \"$(@($env:XDG_DATA_HOME, $env:LOCALAPPDATA)[$null -eq $env:XDG_DATA_HOME])/nvim-data/site/autoload/plug.vim\" -Force\n```\n\n</details>\n\n## Usage\n\nAdd a vim-plug section to your `~/.vimrc` (or `~/.config/nvim/init.vim` for Neovim)\n\n1. Begin the section with `call plug#begin()`\n1. List the plugins with `Plug` commands\n1. End the section with `call plug#end()`\n\nFor example,\n\n```vim\ncall plug#begin()\n\n\" List your plugins here\nPlug 'tpope/vim-sensible'\n\ncall plug#end()\n```\n\nReload the file or restart Vim, then you can,\n\n* `:PlugInstall` to install the plugins\n* `:PlugUpdate` to install or update the plugins\n* `:PlugDiff` to review the changes from the last update\n* `:PlugClean` to remove plugins no longer in the list\n\n> [!NOTE]\n> That's basically all you need to know to get started. The rest of the\n> document is for advanced users who want to know more about the features and\n> options.\n\n> [!TIP]\n> `plug#end()` automatically executes `filetype plugin indent on` and `syntax\n> enable`. We believe this is a good default for most users, but if you don't\n> want this behavior, you can revert the settings after the call.\n>\n> ```vim\n> call plug#end()\n> filetype indent off   \" Disable file-type-specific indentation\n> syntax off            \" Disable syntax highlighting\n> ```\n\n### Getting Help\n\n- See [tutorial] page to learn more about the basics of vim-plug\n- See [tips] and [FAQ] pages for common problems and questions\n\n[tutorial]: https://github.com/junegunn/vim-plug/wiki/tutorial\n[tips]: https://github.com/junegunn/vim-plug/wiki/tips\n[FAQ]: https://github.com/junegunn/vim-plug/wiki/faq\n\n## Examples\n\nThe following examples demonstrate the additional features of vim-plug.\n\n### Vim script example\n\n```vim\ncall plug#begin()\n\" The default plugin directory will be as follows:\n\"   - Vim (Linux/macOS): '~/.vim/plugged'\n\"   - Vim (Windows): '~/vimfiles/plugged'\n\"   - Neovim (Linux/macOS/Windows): stdpath('data') . '/plugged'\n\" You can specify a custom plugin directory by passing it as the argument\n\"   - e.g. `call plug#begin('~/.vim/plugged')`\n\"   - Avoid using standard Vim directory names like 'plugin'\n\n\" Make sure you use single quotes\n\n\" Shorthand notation for GitHub; translates to https://github.com/junegunn/seoul256.vim.git\nPlug 'junegunn/seoul256.vim'\n\n\" Any valid git URL is allowed\nPlug 'https://github.com/junegunn/vim-easy-align.git'\n\n\" Using a tagged release; wildcard allowed (requires git 1.9.2 or above)\nPlug 'fatih/vim-go', { 'tag': '*' }\n\n\" Using a non-default branch\nPlug 'neoclide/coc.nvim', { 'branch': 'release' }\n\n\" Use 'dir' option to install plugin in a non-default directory\nPlug 'junegunn/fzf', { 'dir': '~/.fzf' }\n\n\" Post-update hook: run a shell command after installing or updating the plugin\nPlug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }\n\n\" Post-update hook can be a lambda expression\nPlug 'junegunn/fzf', { 'do': { -> fzf#install() } }\n\n\" If the vim plugin is in a subdirectory, use 'rtp' option to specify its path\nPlug 'nsf/gocode', { 'rtp': 'vim' }\n\n\" On-demand loading: loaded when the specified command is executed\nPlug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }\n\n\" On-demand loading: loaded when a file with a specific file type is opened\nPlug 'tpope/vim-fireplace', { 'for': 'clojure' }\n\n\" Unmanaged plugin (manually installed and updated)\nPlug '~/my-prototype-plugin'\n\n\" Call plug#end to update &runtimepath and initialize the plugin system.\n\" - It automatically executes `filetype plugin indent on` and `syntax enable`\ncall plug#end()\n\" You can revert the settings after the call like so:\n\"   filetype indent off   \" Disable file-type-specific indentation\n\"   syntax off            \" Disable syntax highlighting\n\n\" Color schemes should be loaded after plug#end().\n\" We prepend it with 'silent!' to ignore errors when it's not yet installed.\nsilent! colorscheme seoul256\n```\n\n### Lua example for Neovim\n\nIn Neovim, you can write your configuration in a Lua script file named\n`init.lua`. The following code is the Lua script equivalent to the Vim script\nexample above.\n\n```lua\nlocal vim = vim\nlocal Plug = vim.fn['plug#']\n\nvim.call('plug#begin')\n\n-- Shorthand notation for GitHub; translates to https://github.com/junegunn/seoul256.vim.git\nPlug('junegunn/seoul256.vim')\n\n-- Any valid git URL is allowed\nPlug('https://github.com/junegunn/vim-easy-align.git')\n\n-- Using a tagged release; wildcard allowed (requires git 1.9.2 or above)\nPlug('fatih/vim-go', { ['tag'] = '*' })\n\n-- Using a non-default branch\nPlug('neoclide/coc.nvim', { ['branch'] = 'release' })\n\n-- Use 'dir' option to install plugin in a non-default directory\nPlug('junegunn/fzf', { ['dir'] = '~/.fzf' })\n\n-- Post-update hook: run a shell command after installing or updating the plugin\nPlug('junegunn/fzf', { ['dir'] = '~/.fzf', ['do'] = './install --all' })\n\n-- Post-update hook can be a lambda expression\nPlug('junegunn/fzf', { ['do'] = function()\n  vim.fn['fzf#install']()\nend })\n\n-- If the vim plugin is in a subdirectory, use 'rtp' option to specify its path\nPlug('nsf/gocode', { ['rtp'] = 'vim' })\n\n-- On-demand loading: loaded when the specified command is executed\nPlug('preservim/nerdtree', { ['on'] = 'NERDTreeToggle' })\n\n-- On-demand loading: loaded when a file with a specific file type is opened\nPlug('tpope/vim-fireplace', { ['for'] = 'clojure' })\n\n-- Unmanaged plugin (manually installed and updated)\nPlug('~/my-prototype-plugin')\n\nvim.call('plug#end')\n\n-- Color schemes should be loaded after plug#end().\n-- We prepend it with 'silent!' to ignore errors when it's not yet installed.\nvim.cmd('silent! colorscheme seoul256')\n```\n\n## Commands\n\n| Command                             | Description                                                        |\n| ----------------------------------- | ------------------------------------------------------------------ |\n| `PlugInstall [name ...] [#threads]` | Install plugins                                                    |\n| `PlugUpdate [name ...] [#threads]`  | Install or update plugins                                          |\n| `PlugClean[!]`                      | Remove unlisted plugins (bang version will clean without prompt)   |\n| `PlugUpgrade`                       | Upgrade vim-plug itself                                            |\n| `PlugStatus`                        | Check the status of plugins                                        |\n| `PlugDiff`                          | Examine changes from the previous update and the pending changes   |\n| `PlugSnapshot[!] [output path]`     | Generate script for restoring the current snapshot of the plugins  |\n\n## `Plug` options\n\n| Option                  | Description                                                 |\n| ----------------------- | ----------------------------------------------------------- |\n| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use                  |\n| `rtp`                   | Subdirectory that contains Vim plugin                       |\n| `dir`                   | Custom directory for the plugin                             |\n| `as`                    | Use different name for the plugin                           |\n| `do`                    | Post-update hook (string or funcref)                        |\n| `on`                    | On-demand loading: Commands or `<Plug>`-mappings            |\n| `for`                   | On-demand loading: File types                               |\n| `frozen`                | Do not remove and do not update unless explicitly specified |\n\n## Global options\n\n| Flag                | Default                           | Description                                            |\n| ------------------- | --------------------------------- | ------------------------------------------------------ |\n| `g:plug_threads`    | 16                                | Default number of threads to use                       |\n| `g:plug_timeout`    | 60                                | Time limit of each task in seconds (*Ruby & Python*)   |\n| `g:plug_retries`    | 2                                 | Number of retries in case of timeout (*Ruby & Python*) |\n| `g:plug_shallow`    | 1                                 | Use shallow clone                                      |\n| `g:plug_window`     | `-tabnew`                         | Command to open plug window                            |\n| `g:plug_pwindow`    | `vertical rightbelow new`         | Command to open preview window in `PlugDiff`           |\n| `g:plug_url_format` | `https://git::@github.com/%s.git` | `printf` format to build repo URL (Only applies to the subsequent `Plug` commands) |\n\n\n## Keybindings\n\n- `D` - `PlugDiff`\n- `S` - `PlugStatus`\n- `R` - Retry failed update or installation tasks\n- `U` - Update plugins in the selected range\n- `q` - Abort the running tasks or close the window\n- `:PlugStatus`\n    - `L` - Load plugin\n- `:PlugDiff`\n    - `X` - Revert the update\n\n## Post-update hooks\n\nThere are some plugins that require extra steps after installation or update.\nIn that case, use the `do` option to describe the task to be performed.\n\n```vim\nPlug 'Shougo/vimproc.vim', { 'do': 'make' }\nPlug 'ycm-core/YouCompleteMe', { 'do': './install.py' }\n```\n\nIf the value starts with `:`, it will be recognized as a Vim command.\n\n```vim\nPlug 'fatih/vim-go', { 'do': ':GoInstallBinaries' }\n```\n\nTo call a Vim function, you can pass a lambda expression like so:\n\n```vim\nPlug 'junegunn/fzf', { 'do': { -> fzf#install() } }\n```\n\nIf you need more control, you can pass a reference to a Vim function that\ntakes a dictionary argument.\n\n```vim\nfunction! BuildYCM(info)\n  \" info is a dictionary with 3 fields\n  \" - name:   name of the plugin\n  \" - status: 'installed', 'updated', or 'unchanged'\n  \" - force:  set on PlugInstall! or PlugUpdate!\n  if a:info.status == 'installed' || a:info.force\n    !./install.py\n  endif\nendfunction\n\nPlug 'ycm-core/YouCompleteMe', { 'do': function('BuildYCM') }\n```\n\nA post-update hook is executed inside the directory of the plugin and only run\nwhen the repository has changed, but you can force it to run unconditionally\nwith the bang-versions of the commands: `PlugInstall!` and `PlugUpdate!`.\n\n> [!TIP]\n> Make sure to escape BARs and double-quotes when you write the `do` option\n> inline as they are mistakenly recognized as command separator or the start of\n> the trailing comment.\n>\n> ```vim\n> Plug 'junegunn/fzf', { 'do': 'yes \\| ./install' }\n> ```\n>\n> But you can avoid the escaping if you extract the inline specification using a\n> variable (or any Vim script expression) as follows:\n>\n> ```vim\n> let g:fzf_install = 'yes | ./install'\n> Plug 'junegunn/fzf', { 'do': g:fzf_install }\n> ```\n\n### `PlugInstall!` and `PlugUpdate!`\n\nThe installer takes the following steps when installing/updating a plugin:\n\n1. `git clone` or `git fetch` from its origin\n2. Check out branch, tag, or commit and optionally `git merge` remote branch\n3. If the plugin was updated (or installed for the first time)\n    1. Update submodules\n    2. Execute post-update hooks\n\nThe commands with the `!` suffix ensure that all steps are run unconditionally.\n\n## On-demand loading of plugins\n\n```vim\n\" NERD tree will be loaded on the first invocation of NERDTreeToggle command\nPlug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }\n\n\" Multiple commands\nPlug 'junegunn/vim-github-dashboard', { 'on': ['GHDashboard', 'GHActivity'] }\n\n\" Loaded when clojure file is opened\nPlug 'tpope/vim-fireplace', { 'for': 'clojure' }\n\n\" Multiple file types\nPlug 'kovisoft/paredit', { 'for': ['clojure', 'scheme'] }\n\n\" On-demand loading on both conditions\nPlug 'junegunn/vader.vim',  { 'on': 'Vader', 'for': 'vader' }\n\n\" Code to execute when the plugin is lazily loaded on demand\nPlug 'junegunn/goyo.vim', { 'for': 'markdown' }\nautocmd! User goyo.vim echom 'Goyo is now loaded!'\n```\n\n> [!NOTE]\n> #### Should I set up on-demand loading?\n>\n> You probably don't need to.\n>\n> A properly implemented Vim plugin should already load lazily without any\n> help from a plugin manager (`:help autoload`). So there are few cases where\n> these options actually make much sense. Making a plugin load faster is\n> the responsibility of the plugin developer, not the user. If you find\n> a plugin that takes too long to load, consider opening an issue on the\n> plugin's issue tracker.\n>\n> Let me give you a perspective. The time it takes to load a plugin is usually\n> less than 2 or 3ms on modern computers. So unless you use a very large\n> number of plugins, you are unlikely to save more than 50ms. If you have\n> spent an hour carefully setting up the options to shave off 50ms, you\n> will have to start Vim 72,000 times just to break even. You should ask\n> yourself if that's a good investment of your time.\n>\n> Make sure that you're tackling the right problem by breaking down the\n> startup time of Vim using `--startuptime`.\n>\n> ```sh\n> vim --startuptime /tmp/log\n> ```\n>\n> On-demand loading should only be used as a last resort. It is basically\n> a hacky workaround and is not always guaranteed to work.\n\n> [!TIP]\n> You can pass an empty list to `on` or `for` option to disable the loading\n> of the plugin. You can manually load the plugin using `plug#load(NAMES...)`\n> function.\n>\n> See https://github.com/junegunn/vim-plug/wiki/tips#loading-plugins-manually\n\n\n## Collaborators\n\n- [Jan Edmund Lazo](https://github.com/janlazo) - Windows support\n- [Jeremy Pallats](https://github.com/starcraftman) - Python installer\n\n## License\n\nMIT\n"
  },
  {
    "path": "doc/plug.txt",
    "content": "plug.txt\tplug\tLast change: Jun 1 2024\nPLUG - TABLE OF CONTENTS                                         *plug* *plug-toc*\n==============================================================================\n\n  vim-plug                          |vim-plug|\n    Pros.                           |plug-pros|\n    Installation                    |plug-installation|\n    Usage                           |plug-usage|\n      Getting Help                  |plug-getting-help|\n    Examples                        |plug-examples|\n      Vim script example            |plug-vim-script-example|\n      Lua example for Neovim        |plug-lua-example-for-neovim|\n    Commands                        |plug-commands|\n    Plug options                    |plug-options|\n    Global options                  |plug-global-options|\n    Keybindings                     |plug-keybindings|\n    Post-update hooks               |plug-post-update-hooks|\n      PlugInstall! and PlugUpdate!  |pluginstall-and-plugupdate|\n    On-demand loading of plugins    |plug-on-demand-loading-of-plugins|\n    Collaborators                   |plug-collaborators|\n    License                         |plug-license|\n\nVIM-PLUG                                                              *vim-plug*\n==============================================================================\n\nA minimalist Vim plugin manager.\n\n\nPROS.                                                                *plug-pros*\n==============================================================================\n\n - Minimalist design\n   - Just one file with no dependencies. Super easy to set up.\n   - Concise, intuitive syntax that you can learn within minutes. No\n     boilerplate code required.\n   - No feature bloat\n - Extremely stable with flawless backward compatibility\n   - Works perfectly with all versions of Vim since 2006 and all versions of\n     Neovim ever released\n - {Super-fast}{1} parallel installation/update\n - Creates shallow clones to minimize disk space usage and download time\n - On-demand loading for {faster startup time}{2}\n - Can review and rollback updates\n - Branch/tag/commit support\n - Post-update hooks\n - Support for externally managed plugins\n\n  {1} https://raw.githubusercontent.com/junegunn/i/master/vim-plug/40-in-4.gif\n  {2} https://github.com/junegunn/vim-startuptime-benchmark#result\n\n\nINSTALLATION                                                 *plug-installation*\n==============================================================================\n\n{Download plug.vim}{3} and put it in the \"autoload\" directory.\n\n       {3} https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim\n\n\nUSAGE                                                               *plug-usage*\n==============================================================================\n\nAdd a vim-plug section to your `~/.vimrc` (or `init.vim` for Neovim)\n\n                                                           *plug#begin* *plug#end*\n\n 1. Begin the section with `call plug#begin()`\n 2. List the plugins with `Plug` commands\n 3. End the section with `call plug#end()`\n\nFor example,\n>\n    call plug#begin()\n\n    \" List your plugins here\n    Plug 'tpope/vim-sensible'\n\n    call plug#end()\n<\nReload the file or restart Vim, then you can,\n\n                                            *:PlugInstall* *:PlugUpdate* *:PlugDiff*\n\n - `:PlugInstall` to install the plugins\n - `:PlugUpdate` to install or update the plugins\n - `:PlugDiff` to review the changes from the last update\n\n[!NOTE] That's basically all you need to know to get started. The rest of the\ndocument is for advanced users who want to know more about the features and\noptions.\n\n\n< Getting Help >______________________________________________________________~\n                                                             *plug-getting-help*\n\n - See {tutorial}{4} page to learn more about the basics of vim-plug\n - See {tips}{5} and {FAQ}{6} pages for common problems and questions\n\n                        {4} https://github.com/junegunn/vim-plug/wiki/tutorial\n                        {5} https://github.com/junegunn/vim-plug/wiki/tips\n                        {6} https://github.com/junegunn/vim-plug/wiki/faq\n\n\nEXAMPLES                                                         *plug-examples*\n==============================================================================\n\nThe following examples demonstrate the additional features of vim-plug.\n\n\n< Vim script example >________________________________________________________~\n                                                       *plug-vim-script-example*\n>\n    call plug#begin()\n    \" The default plugin directory will be as follows:\n    \"   - Vim (Linux/macOS): '~/.vim/plugged'\n    \"   - Vim (Windows): '~/vimfiles/plugged'\n    \"   - Neovim (Linux/macOS/Windows): stdpath('data') . '/plugged'\n    \" You can specify a custom plugin directory by passing it as the argument\n    \"   - e.g. `call plug#begin('~/.vim/plugged')`\n    \"   - Avoid using standard Vim directory names like 'plugin'\n\n    \" Make sure you use single quotes\n\n    \" Shorthand notation for GitHub; translates to https://github.com/junegunn/seoul256.vim.git\n    Plug 'junegunn/seoul256.vim'\n\n    \" Any valid git URL is allowed\n    Plug 'https://github.com/junegunn/vim-easy-align.git'\n\n    \" Using a tagged release; wildcard allowed (requires git 1.9.2 or above)\n    Plug 'fatih/vim-go', { 'tag': '*' }\n\n    \" Using a non-default branch\n    Plug 'neoclide/coc.nvim', { 'branch': 'release' }\n\n    \" Use 'dir' option to install plugin in a non-default directory\n    Plug 'junegunn/fzf', { 'dir': '~/.fzf' }\n\n    \" Post-update hook: run a shell command after installing or updating the plugin\n    Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }\n\n    \" Post-update hook can be a lambda expression\n    Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }\n\n    \" If the vim plugin is in a subdirectory, use 'rtp' option to specify its path\n    Plug 'nsf/gocode', { 'rtp': 'vim' }\n\n    \" On-demand loading: loaded when the specified command is executed\n    Plug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }\n\n    \" On-demand loading: loaded when a file with a specific file type is opened\n    Plug 'tpope/vim-fireplace', { 'for': 'clojure' }\n\n    \" Unmanaged plugin (manually installed and updated)\n    Plug '~/my-prototype-plugin'\n\n    \" Call plug#end to update &runtimepath and initialize the plugin system.\n    \" - It automatically executes `filetype plugin indent on` and `syntax enable`\n    call plug#end()\n    \" You can revert the settings after the call like so:\n    \"   filetype indent off   \" Disable file-type-specific indentation\n    \"   syntax off            \" Disable syntax highlighting\n\n    \" Color schemes should be loaded after plug#end().\n    \" We prepend it with 'silent!' to ignore errors when it's not yet installed.\n    silent! colorscheme seoul256\n<\n\n< Lua example for Neovim >____________________________________________________~\n                                                   *plug-lua-example-for-neovim*\n\nIn Neovim, you can write your configuration in a Lua script file named\n`init.lua`. The following code is the Lua script equivalent to the Vim script\nexample above.\n>\n    local vim = vim\n    local Plug = vim.fn['plug#']\n\n    vim.call('plug#begin')\n\n    -- Shorthand notation for GitHub; translates to https://github.com/junegunn/seoul256.vim.git\n    Plug('junegunn/seoul256.vim')\n\n    -- Any valid git URL is allowed\n    Plug('https://github.com/junegunn/vim-easy-align.git')\n\n    -- Using a tagged release; wildcard allowed (requires git 1.9.2 or above)\n    Plug('fatih/vim-go', { ['tag'] = '*' })\n\n    -- Using a non-default branch\n    Plug('neoclide/coc.nvim', { ['branch'] = 'release' })\n\n    -- Use 'dir' option to install plugin in a non-default directory\n    Plug('junegunn/fzf', { ['dir'] = '~/.fzf' })\n\n    -- Post-update hook: run a shell command after installing or updating the plugin\n    Plug('junegunn/fzf', { ['dir'] = '~/.fzf', ['do'] = './install --all' })\n\n    -- Post-update hook can be a lambda expression\n    Plug('junegunn/fzf', { ['do'] = function()\n      vim.fn['fzf#install']()\n    end })\n\n    -- If the vim plugin is in a subdirectory, use 'rtp' option to specify its path\n    Plug('nsf/gocode', { ['rtp'] = 'vim' })\n\n    -- On-demand loading: loaded when the specified command is executed\n    Plug('preservim/nerdtree', { ['on'] = 'NERDTreeToggle' })\n\n    -- On-demand loading: loaded when a file with a specific file type is opened\n    Plug('tpope/vim-fireplace', { ['for'] = 'clojure' })\n\n    -- Unmanaged plugin (manually installed and updated)\n    Plug('~/my-prototype-plugin')\n\n    vim.call('plug#end')\n\n    -- Color schemes should be loaded after plug#end().\n    -- We prepend it with 'silent!' to ignore errors when it's not yet installed.\n    vim.cmd('silent! colorscheme seoul256')\n<\n\nCOMMANDS                                                         *plug-commands*\n==============================================================================\n\n -------------------------------------+------------------------------------------------------------------\n Command                              | Description                                                      ~\n -------------------------------------+------------------------------------------------------------------\n  `PlugInstall [name ...] [#threads]`  | Install plugins\n  `PlugUpdate [name ...] [#threads]`   | Install or update plugins\n  `PlugClean[!]`                       | Remove unlisted plugins (bang version will clean without prompt)\n  `PlugUpgrade`                        | Upgrade vim-plug itself\n  `PlugStatus`                         | Check the status of plugins\n  `PlugDiff`                           | Examine changes from the previous update and the pending changes\n  `PlugSnapshot[!] [output path]`      | Generate script for restoring the current snapshot of the plugins\n -------------------------------------+------------------------------------------------------------------\n\n\nPLUG OPTIONS                                                      *plug-options*\n==============================================================================\n\n                                                               *<Plug>-mappings*\n\n ------------------------+------------------------------------------------------------\n Option                  | Description                                                ~\n ------------------------+------------------------------------------------------------\n  `branch` / `tag` / `commit`  | Branch/tag/commit of the repository to use\n  `rtp`                    | Subdirectory that contains Vim plugin\n  `dir`                    | Custom directory for the plugin\n  `as`                     | Use different name for the plugin\n  `do`                     | Post-update hook (string or funcref)\n  `on`                     | On-demand loading: Commands or <Plug>-mappings\n  `for`                    | On-demand loading: File types\n  `frozen`                 | Do not remove and do not update unless explicitly specified\n ------------------------+------------------------------------------------------------\n\n\nGLOBAL OPTIONS                                             *plug-global-options*\n==============================================================================\n\n     *g:plug_threads* *g:plug_timeout* *g:plug_retries* *g:plug_shallow* *g:plug_window*\n                                              *g:plug_pwindow* *g:plug_url_format*\n\n --------------------+-----------------------------------+-----------------------------------------------------------------------------------\n Flag                | Default                           | Description                                                                       ~\n --------------------+-----------------------------------+-----------------------------------------------------------------------------------\n  `g:plug_threads`     | 16                                | Default number of threads to use\n  `g:plug_timeout`     | 60                                | Time limit of each task in seconds (Ruby & Python)\n  `g:plug_retries`     | 2                                 | Number of retries in case of timeout (Ruby & Python)\n  `g:plug_shallow`     | 1                                 | Use shallow clone\n  `g:plug_window`      |  `-tabnew`                          | Command to open plug window\n  `g:plug_pwindow`     |  `vertical rightbelow new`          | Command to open preview window in  `PlugDiff`\n  `g:plug_url_format`  |  `https://git::@github.com/%s.git`  |  `printf`  format to build repo URL (Only applies to the subsequent  `Plug`  commands)\n --------------------+-----------------------------------+-----------------------------------------------------------------------------------\n\n\nKEYBINDINGS                                                   *plug-keybindings*\n==============================================================================\n\n - `D` - `PlugDiff`\n - `S` - `PlugStatus`\n - `R` - Retry failed update or installation tasks\n - `U` - Update plugins in the selected range\n - `q` - Close the window\n - `:PlugStatus`\n   - `L` - Load plugin\n - `:PlugDiff`\n   - `X` - Revert the update\n\n\nPOST-UPDATE HOOKS                                       *plug-post-update-hooks*\n==============================================================================\n\nThere are some plugins that require extra steps after installation or update.\nIn that case, use the `do` option to describe the task to be performed.\n>\n    Plug 'Shougo/vimproc.vim', { 'do': 'make' }\n    Plug 'ycm-core/YouCompleteMe', { 'do': './install.py' }\n<\nIf the value starts with `:`, it will be recognized as a Vim command.\n>\n    Plug 'fatih/vim-go', { 'do': ':GoInstallBinaries' }\n<\nTo call a Vim function, you can pass a lambda expression like so:\n>\n    Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }\n<\nIf you need more control, you can pass a reference to a Vim function that\ntakes a dictionary argument.\n>\n    function! BuildYCM(info)\n      \" info is a dictionary with 3 fields\n      \" - name:   name of the plugin\n      \" - status: 'installed', 'updated', or 'unchanged'\n      \" - force:  set on PlugInstall! or PlugUpdate!\n      if a:info.status == 'installed' || a:info.force\n        !./install.py\n      endif\n    endfunction\n\n    Plug 'ycm-core/YouCompleteMe', { 'do': function('BuildYCM') }\n<\nA post-update hook is executed inside the directory of the plugin and only run\nwhen the repository has changed, but you can force it to run unconditionally\nwith the bang-versions of the commands: `PlugInstall!` and `PlugUpdate!`.\n\n[!TIP] Make sure to escape BARs and double-quotes when you write the `do`\noption inline as they are mistakenly recognized as command separator or the\nstart of the trailing comment.\n>\n    Plug 'junegunn/fzf', { 'do': 'yes \\| ./install' }\n<\nBut you can avoid the escaping if you extract the inline specification using a\nvariable (or any Vim script expression) as follows:\n>\n    let g:fzf_install = 'yes | ./install'\n    Plug 'junegunn/fzf', { 'do': g:fzf_install }\n<\n\n< PlugInstall! and PlugUpdate! >______________________________________________~\n                                                    *pluginstall-and-plugupdate*\n\nThe installer takes the following steps when installing/updating a plugin:\n\n 1. `git clone` or `git fetch` from its origin\n 2. Check out branch, tag, or commit and optionally `git merge` remote branch\n 3. If the plugin was updated (or installed for the first time)\n   1. Update submodules\n   2. Execute post-update hooks\n\nThe commands with the `!` suffix ensure that all steps are run\nunconditionally.\n\n\nON-DEMAND LOADING OF PLUGINS                 *plug-on-demand-loading-of-plugins*\n==============================================================================\n>\n    \" NERD tree will be loaded on the first invocation of NERDTreeToggle command\n    Plug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }\n\n    \" Multiple commands\n    Plug 'junegunn/vim-github-dashboard', { 'on': ['GHDashboard', 'GHActivity'] }\n\n    \" Loaded when clojure file is opened\n    Plug 'tpope/vim-fireplace', { 'for': 'clojure' }\n\n    \" Multiple file types\n    Plug 'kovisoft/paredit', { 'for': ['clojure', 'scheme'] }\n\n    \" On-demand loading on both conditions\n    Plug 'junegunn/vader.vim',  { 'on': 'Vader', 'for': 'vader' }\n\n    \" Code to execute when the plugin is lazily loaded on demand\n    Plug 'junegunn/goyo.vim', { 'for': 'markdown' }\n    autocmd! User goyo.vim echom 'Goyo is now loaded!'\n<\n[!NOTE] #### Should I set up on-demand loading?\n\nYou probably don't need to.\n\nA properly implemented Vim plugin should already load lazily without any help\nfrom a plugin manager (`:help autoload`). So there are few cases where these\noptions actually make much sense. Making a plugin load faster is the\nresponsibility of the plugin developer, not the user. If you find a plugin\nthat takes too long to load, consider opening an issue on the plugin's issue\ntracker.\n\nLet me give you a perspective. The time it takes to load a plugin is usually\nless than 2 or 3ms on modern computers. So unless you use a very large number\nof plugins, you are unlikely to save more than 50ms. If you have spent an hour\ncarefully setting up the options to shave off 50ms, you will have to start Vim\n72,000 times just to break even. You should ask yourself if that's a good\ninvestment of your time.\n\nMake sure that you're tackling the right problem by breaking down the startup\ntime of Vim using `--startuptime`.\n>\n    vim --startuptime /tmp/log\n<\nOn-demand loading should only be used as a last resort. It is basically a\nhacky workaround and is not always guaranteed to work.\n\n                                                                     *plug#load*\n\n[!TIP] You can pass an empty list to `on` or `for` option to disable the\nloading of the plugin. You can manually load the plugin using\n`plug#load(NAMES...)` function.\n\nSee https://github.com/junegunn/vim-plug/wiki/tips#loading-plugins-manually\n\n\nCOLLABORATORS                                               *plug-collaborators*\n==============================================================================\n\n - {Jan Edmund Lazo}{7} - Windows support\n - {Jeremy Pallats}{8} - Python installer\n\n                                           {7} https://github.com/janlazo\n                                           {8} https://github.com/starcraftman\n\n\nLICENSE                                                           *plug-license*\n==============================================================================\n\nMIT\n\n==============================================================================\nvim:tw=78:sw=2:ts=2:ft=help:norl:nowrap:\n"
  },
  {
    "path": "plug.vim",
    "content": "\" vim-plug: Vim plugin manager\n\" ============================\n\"\n\" 1. Download plug.vim and put it in 'autoload' directory\n\"\n\"   # Vim\n\"   curl -fLo ~/.vim/autoload/plug.vim --create-dirs \\\n\"     https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim\n\"\n\"   # Neovim\n\"   sh -c 'curl -fLo \"${XDG_DATA_HOME:-$HOME/.local/share}\"/nvim/site/autoload/plug.vim --create-dirs \\\n\"     https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'\n\"\n\" 2. Add a vim-plug section to your ~/.vimrc (or ~/.config/nvim/init.vim for Neovim)\n\"\n\"   call plug#begin()\n\"\n\"   \" List your plugins here\n\"   Plug 'tpope/vim-sensible'\n\"\n\"   call plug#end()\n\"\n\" 3. Reload the file or restart Vim, then you can,\n\"\n\"     :PlugInstall to install plugins\n\"     :PlugUpdate  to update plugins\n\"     :PlugDiff    to review the changes from the last update\n\"     :PlugClean   to remove plugins no longer in the list\n\"\n\" For more information, see https://github.com/junegunn/vim-plug\n\"\n\"\n\" Copyright (c) 2024 Junegunn Choi\n\"\n\" MIT License\n\"\n\" Permission is hereby granted, free of charge, to any person obtaining\n\" a copy of this software and associated documentation files (the\n\" \"Software\"), to deal in the Software without restriction, including\n\" without limitation the rights to use, copy, modify, merge, publish,\n\" distribute, sublicense, and/or sell copies of the Software, and to\n\" permit persons to whom the Software is furnished to do so, subject to\n\" the following conditions:\n\"\n\" The above copyright notice and this permission notice shall be\n\" included in all copies or substantial portions of the Software.\n\"\n\" THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n\" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n\" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n\" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n\" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nif exists('g:loaded_plug')\n  finish\nendif\nlet g:loaded_plug = 1\n\nlet s:cpo_save = &cpo\nset cpo&vim\n\nlet s:plug_src = 'https://github.com/junegunn/vim-plug.git'\nlet s:plug_tab = get(s:, 'plug_tab', -1)\nlet s:plug_buf = get(s:, 'plug_buf', -1)\nlet s:mac_gui = has('gui_macvim') && has('gui_running')\nlet s:is_win = has('win32')\nlet s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win)\nlet s:vim8 = has('patch-8.0.0039') && exists('*job_start')\nlet s:shell_error = 0\nif s:is_win && &shellslash\n  set noshellslash\n  let s:me = resolve(expand('<sfile>:p'))\n  set shellslash\nelse\n  let s:me = resolve(expand('<sfile>:p'))\nendif\nlet s:base_spec = { 'branch': '', 'frozen': 0 }\nlet s:TYPE = {\n\\   'string':  type(''),\n\\   'list':    type([]),\n\\   'dict':    type({}),\n\\   'funcref': type(function('call'))\n\\ }\nlet s:loaded = get(s:, 'loaded', {})\nlet s:triggers = get(s:, 'triggers', {})\n\nfunction! s:is_powershell(shell)\n  return a:shell =~# 'powershell\\(\\.exe\\)\\?$' || a:shell =~# 'pwsh\\(\\.exe\\)\\?$'\nendfunction\n\nfunction! s:isabsolute(dir) abort\n  return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\\%(\\\\\\|[A-Z]:\\)')\nendfunction\n\nfunction! s:git_dir(dir) abort\n  let gitdir = s:trim(a:dir) . '/.git'\n  if isdirectory(gitdir)\n    return gitdir\n  endif\n  if !filereadable(gitdir)\n    return ''\n  endif\n  let gitdir = matchstr(get(readfile(gitdir), 0, ''), '^gitdir: \\zs.*')\n  if len(gitdir) && !s:isabsolute(gitdir)\n    let gitdir = a:dir . '/' . gitdir\n  endif\n  return isdirectory(gitdir) ? gitdir : ''\nendfunction\n\nfunction! s:git_origin_url(dir) abort\n  let gitdir = s:git_dir(a:dir)\n  let config = gitdir . '/config'\n  if empty(gitdir) || !filereadable(config)\n    return ''\n  endif\n  return matchstr(join(readfile(config)), '\\[remote \"origin\"\\].\\{-}url\\s*=\\s*\\zs\\S*\\ze')\nendfunction\n\nfunction! s:git_revision(dir) abort\n  let gitdir = s:git_dir(a:dir)\n  let head = gitdir . '/HEAD'\n  if empty(gitdir) || !filereadable(head)\n    return ''\n  endif\n\n  let line = get(readfile(head), 0, '')\n  let ref = matchstr(line, '^ref: \\zs.*')\n  if empty(ref)\n    return line\n  endif\n\n  if filereadable(gitdir . '/' . ref)\n    return get(readfile(gitdir . '/' . ref), 0, '')\n  endif\n\n  if filereadable(gitdir . '/packed-refs')\n    for line in readfile(gitdir . '/packed-refs')\n      if line =~# ' ' . ref\n        return matchstr(line, '^[0-9a-f]*')\n      endif\n    endfor\n  endif\n\n  return ''\nendfunction\n\nfunction! s:git_local_branch(dir) abort\n  let gitdir = s:git_dir(a:dir)\n  let head = gitdir . '/HEAD'\n  if empty(gitdir) || !filereadable(head)\n    return ''\n  endif\n  let branch = matchstr(get(readfile(head), 0, ''), '^ref: refs/heads/\\zs.*')\n  return len(branch) ? branch : 'HEAD'\nendfunction\n\nfunction! s:git_origin_branch(spec)\n  if len(a:spec.branch)\n    return a:spec.branch\n  endif\n\n  \" The file may not be present if this is a local repository\n  let gitdir = s:git_dir(a:spec.dir)\n  let origin_head = gitdir.'/refs/remotes/origin/HEAD'\n  if len(gitdir) && filereadable(origin_head)\n    return matchstr(get(readfile(origin_head), 0, ''),\n                  \\ '^ref: refs/remotes/origin/\\zs.*')\n  endif\n\n  \" The command may not return the name of a branch in detached HEAD state\n  let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir))\n  return s:shell_error ? '' : result[-1]\nendfunction\n\nif s:is_win\n  function! s:plug_call(fn, ...)\n    let shellslash = &shellslash\n    try\n      set noshellslash\n      return call(a:fn, a:000)\n    finally\n      let &shellslash = shellslash\n    endtry\n  endfunction\nelse\n  function! s:plug_call(fn, ...)\n    return call(a:fn, a:000)\n  endfunction\nendif\n\nfunction! s:plug_getcwd()\n  return s:plug_call('getcwd')\nendfunction\n\nfunction! s:plug_fnamemodify(fname, mods)\n  return s:plug_call('fnamemodify', a:fname, a:mods)\nendfunction\n\nfunction! s:plug_expand(fmt)\n  return s:plug_call('expand', a:fmt, 1)\nendfunction\n\nfunction! s:plug_tempname()\n  return s:plug_call('tempname')\nendfunction\n\nfunction! plug#begin(...)\n  if a:0 > 0\n    let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p'))\n  elseif exists('g:plug_home')\n    let home = s:path(g:plug_home)\n  elseif has('nvim')\n    let home = stdpath('data') . '/plugged'\n  elseif !empty(&rtp)\n    let home = s:path(split(&rtp, ',')[0]) . '/plugged'\n  else\n    return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')\n  endif\n  if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp\n    return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.')\n  endif\n\n  let g:plug_home = home\n  let g:plugs = {}\n  let g:plugs_order = []\n  let s:triggers = {}\n\n  call s:define_commands()\n  return 1\nendfunction\n\nfunction! s:define_commands()\n  command! -nargs=+ -bar Plug call plug#(<args>)\n  if !executable('git')\n    return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.')\n  endif\n  if has('win32')\n  \\ && &shellslash\n  \\ && (&shell =~# 'cmd\\(\\.exe\\)\\?$' || s:is_powershell(&shell))\n    return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.')\n  endif\n  if !has('nvim')\n    \\ && (has('win32') || has('win32unix'))\n    \\ && !has('multi_byte')\n    return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.')\n  endif\n  command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>])\n  command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate  call s:update(<bang>0, [<f-args>])\n  command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0)\n  command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif\n  command! -nargs=0 -bar PlugStatus  call s:status()\n  command! -nargs=0 -bar PlugDiff    call s:diff()\n  command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(<bang>0, <f-args>)\nendfunction\n\nfunction! s:to_a(v)\n  return type(a:v) == s:TYPE.list ? a:v : [a:v]\nendfunction\n\nfunction! s:to_s(v)\n  return type(a:v) == s:TYPE.string ? a:v : join(a:v, \"\\n\") . \"\\n\"\nendfunction\n\nfunction! s:glob(from, pattern)\n  return s:lines(globpath(a:from, a:pattern))\nendfunction\n\nfunction! s:source(from, ...)\n  let found = 0\n  for pattern in a:000\n    for vim in s:glob(a:from, pattern)\n      execute 'source' s:esc(vim)\n      let found = 1\n    endfor\n  endfor\n  return found\nendfunction\n\nfunction! s:assoc(dict, key, val)\n  let a:dict[a:key] = add(get(a:dict, a:key, []), a:val)\nendfunction\n\nfunction! s:ask(message, ...)\n  call inputsave()\n  echohl WarningMsg\n  let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) '))\n  echohl None\n  call inputrestore()\n  echo \"\\r\"\n  return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0\nendfunction\n\nfunction! s:ask_no_interrupt(...)\n  try\n    return call('s:ask', a:000)\n  catch\n    return 0\n  endtry\nendfunction\n\nfunction! s:lazy(plug, opt)\n  return has_key(a:plug, a:opt) &&\n        \\ (empty(s:to_a(a:plug[a:opt]))         ||\n        \\  !isdirectory(a:plug.dir)             ||\n        \\  len(s:glob(s:rtp(a:plug), 'plugin')) ||\n        \\  len(s:glob(s:rtp(a:plug), 'after/plugin')))\nendfunction\n\nfunction! plug#end()\n  if !exists('g:plugs')\n    return s:err('plug#end() called without calling plug#begin() first')\n  endif\n\n  if exists('#PlugLOD')\n    augroup PlugLOD\n      autocmd!\n    augroup END\n    augroup! PlugLOD\n  endif\n  let lod = { 'ft': {}, 'map': {}, 'cmd': {} }\n\n  if get(g:, 'did_load_filetypes', 0)\n    filetype off\n  endif\n  for name in g:plugs_order\n    if !has_key(g:plugs, name)\n      continue\n    endif\n    let plug = g:plugs[name]\n    if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for')\n      let s:loaded[name] = 1\n      continue\n    endif\n\n    if has_key(plug, 'on')\n      let s:triggers[name] = { 'map': [], 'cmd': [] }\n      for cmd in s:to_a(plug.on)\n        if cmd =~? '^<Plug>.\\+'\n          if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i'))\n            call s:assoc(lod.map, cmd, name)\n          endif\n          call add(s:triggers[name].map, cmd)\n        elseif cmd =~# '^[A-Z]'\n          let cmd = substitute(cmd, '!*$', '', '')\n          if exists(':'.cmd) != 2\n            call s:assoc(lod.cmd, cmd, name)\n          endif\n          call add(s:triggers[name].cmd, cmd)\n        else\n          call s:err('Invalid `on` option: '.cmd.\n          \\ '. Should start with an uppercase letter or `<Plug>`.')\n        endif\n      endfor\n    endif\n\n    if has_key(plug, 'for')\n      let types = s:to_a(plug.for)\n      if !empty(types)\n        augroup filetypedetect\n        call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim')\n        if has('nvim-0.5.0')\n          call s:source(s:rtp(plug), 'ftdetect/**/*.lua', 'after/ftdetect/**/*.lua')\n        endif\n        augroup END\n      endif\n      for type in types\n        call s:assoc(lod.ft, type, name)\n      endfor\n    endif\n  endfor\n\n  for [cmd, names] in items(lod.cmd)\n    execute printf(\n    \\ has('patch-7.4.1898')\n    \\ ? 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, \"<bang>\", <line1>, <line2>, <q-args>, <q-mods> ,%s)'\n    \\ : 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, \"<bang>\", <line1>, <line2>, <q-args>, %s)'\n    \\ , cmd, string(cmd), string(names))\n  endfor\n\n  for [map, names] in items(lod.map)\n    for [mode, map_prefix, key_prefix] in\n          \\ [['i', '<C-\\><C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']]\n      execute printf(\n      \\ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, %s, \"%s\")<CR>',\n      \\ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix)\n    endfor\n  endfor\n\n  for [ft, names] in items(lod.ft)\n    augroup PlugLOD\n      execute printf('autocmd FileType %s call <SID>lod_ft(%s, %s)',\n            \\ ft, string(ft), string(names))\n    augroup END\n  endfor\n\n  call s:reorg_rtp()\n  filetype plugin indent on\n  if has('vim_starting')\n    if has('syntax') && !exists('g:syntax_on')\n      syntax enable\n    end\n  else\n    call s:reload_plugins()\n  endif\nendfunction\n\nfunction! s:loaded_names()\n  return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)')\nendfunction\n\nfunction! s:load_plugin(spec)\n  call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim')\n  if has('nvim-0.5.0')\n    call s:source(s:rtp(a:spec), 'plugin/**/*.lua', 'after/plugin/**/*.lua')\n  endif\nendfunction\n\nfunction! s:reload_plugins()\n  for name in s:loaded_names()\n    call s:load_plugin(g:plugs[name])\n  endfor\nendfunction\n\nfunction! s:trim(str)\n  return substitute(a:str, '[\\/]\\+$', '', '')\nendfunction\n\nfunction! s:version_requirement(val, min)\n  for idx in range(0, len(a:min) - 1)\n    let v = get(a:val, idx, 0)\n    if     v < a:min[idx] | return 0\n    elseif v > a:min[idx] | return 1\n    endif\n  endfor\n  return 1\nendfunction\n\nfunction! s:git_version_requirement(...)\n  if !exists('s:git_version')\n    let s:git_version = map(split(split(s:system(['git', '--version']))[2], '\\.'), 'str2nr(v:val)')\n  endif\n  return s:version_requirement(s:git_version, a:000)\nendfunction\n\nfunction! s:progress_opt(base)\n  return a:base && !s:is_win &&\n        \\ s:git_version_requirement(1, 7, 1) ? '--progress' : ''\nendfunction\n\nfunction! s:rtp(spec)\n  return s:path(a:spec.dir . get(a:spec, 'rtp', ''))\nendfunction\n\nif s:is_win\n  function! s:path(path)\n    return s:trim(substitute(a:path, '/', '\\', 'g'))\n  endfunction\n\n  function! s:dirpath(path)\n    return s:path(a:path) . '\\'\n  endfunction\n\n  function! s:is_local_plug(repo)\n    return a:repo =~? '^[a-z]:\\|^[%~]'\n  endfunction\n\n  \" Copied from fzf\n  function! s:wrap_cmds(cmds)\n    let cmds = [\n      \\ '@echo off',\n      \\ 'setlocal enabledelayedexpansion']\n    \\ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])\n    \\ + ['endlocal']\n    if has('iconv')\n      if !exists('s:codepage')\n        let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)\n      endif\n      return map(cmds, printf('iconv(v:val.\"\\r\", \"%s\", \"cp%d\")', &encoding, s:codepage))\n    endif\n    return map(cmds, 'v:val.\"\\r\"')\n  endfunction\n\n  function! s:batchfile(cmd)\n    let batchfile = s:plug_tempname().'.bat'\n    call writefile(s:wrap_cmds(a:cmd), batchfile)\n    let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0})\n    if s:is_powershell(&shell)\n      let cmd = '& ' . cmd\n    endif\n    return [batchfile, cmd]\n  endfunction\nelse\n  function! s:path(path)\n    return s:trim(a:path)\n  endfunction\n\n  function! s:dirpath(path)\n    return substitute(a:path, '[/\\\\]*$', '/', '')\n  endfunction\n\n  function! s:is_local_plug(repo)\n    return a:repo[0] =~ '[/$~]'\n  endfunction\nendif\n\nfunction! s:err(msg)\n  echohl ErrorMsg\n  echom '[vim-plug] '.a:msg\n  echohl None\nendfunction\n\nfunction! s:warn(cmd, msg)\n  echohl WarningMsg\n  execute a:cmd 'a:msg'\n  echohl None\nendfunction\n\nfunction! s:esc(path)\n  return escape(a:path, ' ')\nendfunction\n\nfunction! s:escrtp(path)\n  return escape(a:path, ' ,')\nendfunction\n\nfunction! s:remove_rtp()\n  for name in s:loaded_names()\n    let rtp = s:rtp(g:plugs[name])\n    execute 'set rtp-='.s:escrtp(rtp)\n    let after = globpath(rtp, 'after')\n    if isdirectory(after)\n      execute 'set rtp-='.s:escrtp(after)\n    endif\n  endfor\nendfunction\n\nfunction! s:reorg_rtp()\n  if !empty(s:first_rtp)\n    execute 'set rtp-='.s:first_rtp\n    execute 'set rtp-='.s:last_rtp\n  endif\n\n  \" &rtp is modified from outside\n  if exists('s:prtp') && s:prtp !=# &rtp\n    call s:remove_rtp()\n    unlet! s:middle\n  endif\n\n  let s:middle = get(s:, 'middle', &rtp)\n  let rtps     = map(s:loaded_names(), 's:rtp(g:plugs[v:val])')\n  let afters   = filter(map(copy(rtps), 'globpath(v:val, \"after\")'), '!empty(v:val)')\n  let rtp      = join(map(rtps, 'escape(v:val, \",\")'), ',')\n                 \\ . ','.s:middle.','\n                 \\ . join(map(afters, 'escape(v:val, \",\")'), ',')\n  let &rtp     = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\\|,$', '', 'g')\n  let s:prtp   = &rtp\n\n  if !empty(s:first_rtp)\n    execute 'set rtp^='.s:first_rtp\n    execute 'set rtp+='.s:last_rtp\n  endif\nendfunction\n\nfunction! s:doautocmd(...)\n  if exists('#'.join(a:000, '#'))\n    execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000)\n  endif\nendfunction\n\nfunction! s:dobufread(names)\n  for name in a:names\n    let path = s:rtp(g:plugs[name])\n    for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin']\n      if len(finddir(dir, path))\n        if exists('#BufRead')\n          doautocmd BufRead\n        endif\n        return\n      endif\n    endfor\n  endfor\nendfunction\n\nfunction! plug#load(...)\n  if a:0 == 0\n    return s:err('Argument missing: plugin name(s) required')\n  endif\n  if !exists('g:plugs')\n    return s:err('plug#begin was not called')\n  endif\n  let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000\n  let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)')\n  if !empty(unknowns)\n    let s = len(unknowns) > 1 ? 's' : ''\n    return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', ')))\n  end\n  let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)')\n  if !empty(unloaded)\n    for name in unloaded\n      call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])\n    endfor\n    call s:dobufread(unloaded)\n    return 1\n  end\n  return 0\nendfunction\n\nfunction! s:remove_triggers(name)\n  if !has_key(s:triggers, a:name)\n    return\n  endif\n  for cmd in s:triggers[a:name].cmd\n    execute 'silent! delc' cmd\n  endfor\n  for map in s:triggers[a:name].map\n    execute 'silent! unmap' map\n    execute 'silent! iunmap' map\n  endfor\n  call remove(s:triggers, a:name)\nendfunction\n\nfunction! s:lod(names, types, ...)\n  for name in a:names\n    call s:remove_triggers(name)\n    let s:loaded[name] = 1\n  endfor\n  call s:reorg_rtp()\n\n  for name in a:names\n    let rtp = s:rtp(g:plugs[name])\n    for dir in a:types\n      call s:source(rtp, dir.'/**/*.vim')\n      if has('nvim-0.5.0')  \" see neovim#14686\n        call s:source(rtp, dir.'/**/*.lua')\n      endif\n    endfor\n    if a:0\n      if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2))\n        execute 'runtime' a:1\n      endif\n      call s:source(rtp, a:2)\n    endif\n    call s:doautocmd('User', name)\n  endfor\nendfunction\n\nfunction! s:lod_ft(pat, names)\n  let syn = 'syntax/'.a:pat.'.vim'\n  call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn)\n  execute 'autocmd! PlugLOD FileType' a:pat\n  call s:doautocmd('filetypeplugin', 'FileType')\n  call s:doautocmd('filetypeindent', 'FileType')\nendfunction\n\nif has('patch-7.4.1898')\n  function! s:lod_cmd(cmd, bang, l1, l2, args, mods, names)\n    call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])\n    call s:dobufread(a:names)\n    execute printf('%s %s%s%s %s', a:mods, (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)\n  endfunction\nelse\n  function! s:lod_cmd(cmd, bang, l1, l2, args, names)\n    call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])\n    call s:dobufread(a:names)\n    execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)\n  endfunction\nendif\n\nfunction! s:lod_map(map, names, with_prefix, prefix)\n  call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])\n  call s:dobufread(a:names)\n  let extra = ''\n  while 1\n    let c = getchar(0)\n    if c == 0\n      break\n    endif\n    let extra .= nr2char(c)\n  endwhile\n\n  if a:with_prefix\n    let prefix = v:count ? v:count : ''\n    let prefix .= '\"'.v:register.a:prefix\n    if mode(1) == 'no'\n      if v:operator == 'c'\n        let prefix = \"\\<esc>\" . prefix\n      endif\n      let prefix .= v:operator\n    endif\n    call feedkeys(prefix, 'n')\n  endif\n  call feedkeys(substitute(a:map, '^<Plug>', \"\\<Plug>\", '') . extra)\nendfunction\n\nfunction! plug#(repo, ...)\n  if a:0 > 1\n    return s:err('Invalid number of arguments (1..2)')\n  endif\n\n  try\n    let repo = s:trim(a:repo)\n    let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec\n    let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\\.git$??'))\n    let spec = extend(s:infer_properties(name, repo), opts)\n    if !has_key(g:plugs, name)\n      call add(g:plugs_order, name)\n    endif\n    let g:plugs[name] = spec\n    let s:loaded[name] = get(s:loaded, name, 0)\n  catch\n    return s:err(repo . ' ' . v:exception)\n  endtry\nendfunction\n\nfunction! s:parse_options(arg)\n  let opts = copy(s:base_spec)\n  let type = type(a:arg)\n  let opt_errfmt = 'Invalid argument for \"%s\" option of :Plug (expected: %s)'\n  if type == s:TYPE.string\n    if empty(a:arg)\n      throw printf(opt_errfmt, 'tag', 'string')\n    endif\n    let opts.tag = a:arg\n  elseif type == s:TYPE.dict\n    for opt in ['branch', 'tag', 'commit', 'rtp', 'dir', 'as']\n      if has_key(a:arg, opt)\n      \\ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))\n        throw printf(opt_errfmt, opt, 'string')\n      endif\n    endfor\n    for opt in ['on', 'for']\n      if has_key(a:arg, opt)\n      \\ && type(a:arg[opt]) != s:TYPE.list\n      \\ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))\n        throw printf(opt_errfmt, opt, 'string or list')\n      endif\n    endfor\n    if has_key(a:arg, 'do')\n      \\ && type(a:arg.do) != s:TYPE.funcref\n      \\ && (type(a:arg.do) != s:TYPE.string || empty(a:arg.do))\n        throw printf(opt_errfmt, 'do', 'string or funcref')\n    endif\n    call extend(opts, a:arg)\n    if has_key(opts, 'dir')\n      let opts.dir = s:dirpath(s:plug_expand(opts.dir))\n    endif\n  else\n    throw 'Invalid argument type (expected: string or dictionary)'\n  endif\n  return opts\nendfunction\n\nfunction! s:infer_properties(name, repo)\n  let repo = a:repo\n  if s:is_local_plug(repo)\n    return { 'dir': s:dirpath(s:plug_expand(repo)) }\n  else\n    if repo =~ ':'\n      let uri = repo\n    else\n      if repo !~ '/'\n        throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo)\n      endif\n      let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git')\n      let uri = printf(fmt, repo)\n    endif\n    return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri }\n  endif\nendfunction\n\nfunction! s:install(force, names)\n  call s:update_impl(0, a:force, a:names)\nendfunction\n\nfunction! s:update(force, names)\n  call s:update_impl(1, a:force, a:names)\nendfunction\n\nfunction! plug#helptags()\n  if !exists('g:plugs')\n    return s:err('plug#begin was not called')\n  endif\n  for spec in values(g:plugs)\n    let docd = join([s:rtp(spec), 'doc'], '/')\n    if isdirectory(docd)\n      silent! execute 'helptags' s:esc(docd)\n    endif\n  endfor\n  return 1\nendfunction\n\nfunction! s:syntax()\n  syntax clear\n  syntax region plug1 start=/\\%1l/ end=/\\%2l/ contains=plugNumber\n  syntax region plug2 start=/\\%2l/ end=/\\%3l/ contains=plugBracket,plugX,plugAbort\n  syn match plugNumber /[0-9]\\+[0-9.]*/ contained\n  syn match plugBracket /[[\\]]/ contained\n  syn match plugX /x/ contained\n  syn match plugAbort /\\~/ contained\n  syn match plugDash /^-\\{1}\\ /\n  syn match plugPlus /^+/\n  syn match plugStar /^*/\n  syn match plugMessage /\\(^- \\)\\@<=.*/\n  syn match plugName /\\(^- \\)\\@<=[^ ]*:/\n  syn match plugSha /\\%(: \\)\\@<=[0-9a-f]\\{4,}$/\n  syn match plugTag /(tag: [^)]\\+)/\n  syn match plugInstall /\\(^+ \\)\\@<=[^:]*/\n  syn match plugUpdate /\\(^* \\)\\@<=[^:]*/\n  syn match plugCommit /^  \\X*[0-9a-f]\\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag\n  syn match plugEdge /^  \\X\\+$/\n  syn match plugEdge /^  \\X*/ contained nextgroup=plugSha\n  syn match plugSha /[0-9a-f]\\{7,9}/ contained\n  syn match plugRelDate /([^)]*)$/ contained\n  syn match plugNotLoaded /(not loaded)$/\n  syn match plugError /^x.*/\n  syn region plugDeleted start=/^\\~ .*/ end=/^\\ze\\S/\n  syn match plugH2 /^.*:\\n-\\+$/\n  syn match plugH2 /^-\\{2,}/\n  syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean\n  hi def link plug1       Title\n  hi def link plug2       Repeat\n  hi def link plugH2      Type\n  hi def link plugX       Exception\n  hi def link plugAbort   Ignore\n  hi def link plugBracket Structure\n  hi def link plugNumber  Number\n\n  hi def link plugDash    Special\n  hi def link plugPlus    Constant\n  hi def link plugStar    Boolean\n\n  hi def link plugMessage Function\n  hi def link plugName    Label\n  hi def link plugInstall Function\n  hi def link plugUpdate  Type\n\n  hi def link plugError   Error\n  hi def link plugDeleted Ignore\n  hi def link plugRelDate Comment\n  hi def link plugEdge    PreProc\n  hi def link plugSha     Identifier\n  hi def link plugTag     Constant\n\n  hi def link plugNotLoaded Comment\nendfunction\n\nfunction! s:lpad(str, len)\n  return a:str . repeat(' ', a:len - len(a:str))\nendfunction\n\nfunction! s:lines(msg)\n  return split(a:msg, \"[\\r\\n]\")\nendfunction\n\nfunction! s:lastline(msg)\n  return get(s:lines(a:msg), -1, '')\nendfunction\n\nfunction! s:new_window()\n  execute get(g:, 'plug_window', '-tabnew')\nendfunction\n\nfunction! s:plug_window_exists()\n  let buflist = tabpagebuflist(s:plug_tab)\n  return !empty(buflist) && index(buflist, s:plug_buf) >= 0\nendfunction\n\nfunction! s:switch_in()\n  if !s:plug_window_exists()\n    return 0\n  endif\n\n  if winbufnr(0) != s:plug_buf\n    let s:pos = [tabpagenr(), winnr(), winsaveview()]\n    execute 'normal!' s:plug_tab.'gt'\n    let winnr = bufwinnr(s:plug_buf)\n    execute winnr.'wincmd w'\n    call add(s:pos, winsaveview())\n  else\n    let s:pos = [winsaveview()]\n  endif\n\n  setlocal modifiable\n  return 1\nendfunction\n\nfunction! s:switch_out(...)\n  call winrestview(s:pos[-1])\n  setlocal nomodifiable\n  if a:0 > 0\n    execute a:1\n  endif\n\n  if len(s:pos) > 1\n    execute 'normal!' s:pos[0].'gt'\n    execute s:pos[1] 'wincmd w'\n    call winrestview(s:pos[2])\n  endif\nendfunction\n\nfunction! s:finish_bindings()\n  nnoremap <silent> <buffer> R  :call <SID>retry()<cr>\n  nnoremap <silent> <buffer> D  :PlugDiff<cr>\n  nnoremap <silent> <buffer> S  :PlugStatus<cr>\n  nnoremap <silent> <buffer> U  :call <SID>status_update()<cr>\n  xnoremap <silent> <buffer> U  :call <SID>status_update()<cr>\n  nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr>\n  nnoremap <silent> <buffer> [[ :silent! call <SID>section('b')<cr>\nendfunction\n\nfunction! s:prepare(...)\n  if empty(s:plug_getcwd())\n    throw 'Invalid current working directory. Cannot proceed.'\n  endif\n\n  for evar in ['$GIT_DIR', '$GIT_WORK_TREE']\n    if exists(evar)\n      throw evar.' detected. Cannot proceed.'\n    endif\n  endfor\n\n  call s:job_abort(0)\n  if s:switch_in()\n    if b:plug_preview == 1\n      pc\n    endif\n    enew\n  else\n    call s:new_window()\n  endif\n\n  nnoremap <silent> <buffer> q :call <SID>close_pane()<cr>\n  if a:0 == 0\n    call s:finish_bindings()\n  endif\n  let b:plug_preview = -1\n  let s:plug_tab = tabpagenr()\n  let s:plug_buf = winbufnr(0)\n  call s:assign_name()\n\n  for k in ['<cr>', 'L', 'o', 'X', 'd', 'dd']\n    execute 'silent! unmap <buffer>' k\n  endfor\n  setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell\n  if exists('+colorcolumn')\n    setlocal colorcolumn=\n  endif\n  setf vim-plug\n  if exists('g:syntax_on')\n    call s:syntax()\n  endif\nendfunction\n\nfunction! s:close_pane()\n  if b:plug_preview == 1\n    pc\n    let b:plug_preview = -1\n  elseif exists('s:jobs') && !empty(s:jobs)\n    call s:job_abort(1)\n  else\n    bd\n  endif\nendfunction\n\nfunction! s:assign_name()\n  \" Assign buffer name\n  let prefix = '[Plugins]'\n  let name   = prefix\n  let idx    = 2\n  while bufexists(name)\n    let name = printf('%s (%s)', prefix, idx)\n    let idx = idx + 1\n  endwhile\n  silent! execute 'f' fnameescape(name)\nendfunction\n\nfunction! s:chsh(swap)\n  let prev = [&shell, &shellcmdflag, &shellredir]\n  if !s:is_win\n    set shell=sh\n  endif\n  if a:swap\n    if s:is_powershell(&shell)\n      let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s'\n    elseif &shell =~# 'sh' || &shell =~# 'cmd\\(\\.exe\\)\\?$'\n      set shellredir=>%s\\ 2>&1\n    endif\n  endif\n  return prev\nendfunction\n\nfunction! s:bang(cmd, ...)\n  let batchfile = ''\n  try\n    let [sh, shellcmdflag, shrd] = s:chsh(a:0)\n    \" FIXME: Escaping is incomplete. We could use shellescape with eval,\n    \"        but it won't work on Windows.\n    let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd\n    if s:is_win\n      let [batchfile, cmd] = s:batchfile(cmd)\n    endif\n    let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%')\n    execute \"normal! :execute g:_plug_bang\\<cr>\\<cr>\"\n  finally\n    unlet g:_plug_bang\n    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]\n    if s:is_win && filereadable(batchfile)\n      call delete(batchfile)\n    endif\n  endtry\n  return v:shell_error ? 'Exit status: ' . v:shell_error : ''\nendfunction\n\nfunction! s:regress_bar()\n  let bar = substitute(getline(2)[1:-2], '.*\\zs=', 'x', '')\n  call s:progress_bar(2, bar, len(bar))\nendfunction\n\nfunction! s:is_updated(dir)\n  return !empty(s:system_chomp(['git', 'log', '--pretty=format:%h', 'HEAD...HEAD@{1}'], a:dir))\nendfunction\n\nfunction! s:do(pull, force, todo)\n  if has('nvim')\n    \" Reset &rtp to invalidate Neovim cache of loaded Lua modules\n    \" See https://github.com/junegunn/vim-plug/pull/1157#issuecomment-1809226110\n    let &rtp = &rtp\n  endif\n  for [name, spec] in items(a:todo)\n    if !isdirectory(spec.dir)\n      continue\n    endif\n    let installed = has_key(s:update.new, name)\n    let updated = installed ? 0 :\n      \\ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir))\n    if a:force || installed || updated\n      execute 'cd' s:esc(spec.dir)\n      call append(3, '- Post-update hook for '. name .' ... ')\n      let error = ''\n      let type = type(spec.do)\n      if type == s:TYPE.string\n        if spec.do[0] == ':'\n          if !get(s:loaded, name, 0)\n            let s:loaded[name] = 1\n            call s:reorg_rtp()\n          endif\n          call s:load_plugin(spec)\n          try\n            execute spec.do[1:]\n          catch\n            let error = v:exception\n          endtry\n          if !s:plug_window_exists()\n            cd -\n            throw 'Warning: vim-plug was terminated by the post-update hook of '.name\n          endif\n        else\n          let error = s:bang(spec.do)\n        endif\n      elseif type == s:TYPE.funcref\n        try\n          call s:load_plugin(spec)\n          let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')\n          call spec.do({ 'name': name, 'status': status, 'force': a:force })\n        catch\n          let error = v:exception\n        endtry\n      else\n        let error = 'Invalid hook type'\n      endif\n      call s:switch_in()\n      call setline(4, empty(error) ? (getline(4) . 'OK')\n                                 \\ : ('x' . getline(4)[1:] . error))\n      if !empty(error)\n        call add(s:update.errors, name)\n        call s:regress_bar()\n      endif\n      cd -\n    endif\n  endfor\nendfunction\n\nfunction! s:hash_match(a, b)\n  return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0\nendfunction\n\nfunction! s:disable_credential_helper()\n  return s:git_version_requirement(2) && get(g:, 'plug_disable_credential_helper', 1)\nendfunction\n\nfunction! s:checkout(spec)\n  let sha = a:spec.commit\n  let output = s:git_revision(a:spec.dir)\n  let error = 0\n  if !empty(output) && !s:hash_match(sha, s:lines(output)[0])\n    let credential_helper = s:disable_credential_helper() ? '-c credential.helper= ' : ''\n    let output = s:system(\n          \\ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)\n    let error = s:shell_error\n  endif\n  return [output, error]\nendfunction\n\nfunction! s:finish(pull)\n  let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen'))\n  if new_frozen\n    let s = new_frozen > 1 ? 's' : ''\n    call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s))\n  endif\n  call append(3, '- Finishing ... ') | 4\n  redraw\n  call plug#helptags()\n  call plug#end()\n  call setline(4, getline(4) . 'Done!')\n  redraw\n  let msgs = []\n  if !empty(s:update.errors)\n    call add(msgs, \"Press 'R' to retry.\")\n  endif\n  if a:pull && len(s:update.new) < len(filter(getline(5, '$'),\n                \\ \"v:val =~ '^- ' && v:val !~# 'Already up.to.date'\"))\n    call add(msgs, \"Press 'D' to see the updated changes.\")\n  endif\n  echo join(msgs, ' ')\n  call s:finish_bindings()\nendfunction\n\nfunction! s:retry()\n  if empty(s:update.errors)\n    return\n  endif\n  echo\n  call s:update_impl(s:update.pull, s:update.force,\n        \\ extend(copy(s:update.errors), [s:update.threads]))\nendfunction\n\nfunction! s:is_managed(name)\n  return has_key(g:plugs[a:name], 'uri')\nendfunction\n\nfunction! s:names(...)\n  return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)'))\nendfunction\n\nfunction! s:check_ruby()\n  silent! ruby require 'thread'; VIM::command(\"let g:plug_ruby = '#{RUBY_VERSION}'\")\n  if !exists('g:plug_ruby')\n    redraw!\n    return s:warn('echom', 'Warning: Ruby interface is broken')\n  endif\n  let ruby_version = split(g:plug_ruby, '\\.')\n  unlet g:plug_ruby\n  return s:version_requirement(ruby_version, [1, 8, 7])\nendfunction\n\nfunction! s:update_impl(pull, force, args) abort\n  let sync = index(a:args, '--sync') >= 0 || has('vim_starting')\n  let args = filter(copy(a:args), 'v:val != \"--sync\"')\n  let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ?\n                  \\ remove(args, -1) : get(g:, 'plug_threads', 16)\n\n  let managed = filter(deepcopy(g:plugs), 's:is_managed(v:key)')\n  let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') :\n                         \\ filter(managed, 'index(args, v:key) >= 0')\n\n  if empty(todo)\n    return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install'))\n  endif\n\n  if !s:is_win && s:git_version_requirement(2, 3)\n    let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : ''\n    let $GIT_TERMINAL_PROMPT = 0\n    for plug in values(todo)\n      let plug.uri = substitute(plug.uri,\n            \\ '^https://git::@github\\.com', 'https://github.com', '')\n    endfor\n  endif\n\n  if !isdirectory(g:plug_home)\n    try\n      call mkdir(g:plug_home, 'p')\n    catch\n      return s:err(printf('Invalid plug directory: %s. '.\n              \\ 'Try to call plug#begin with a valid directory', g:plug_home))\n    endtry\n  endif\n\n  if has('nvim') && !exists('*jobwait') && threads > 1\n    call s:warn('echom', '[vim-plug] Update Neovim for parallel installer')\n  endif\n\n  let use_job = s:nvim || s:vim8\n  let python = (has('python') || has('python3')) && !use_job\n  let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby()\n\n  let s:update = {\n    \\ 'start':   reltime(),\n    \\ 'all':     todo,\n    \\ 'todo':    copy(todo),\n    \\ 'errors':  [],\n    \\ 'pull':    a:pull,\n    \\ 'force':   a:force,\n    \\ 'new':     {},\n    \\ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1,\n    \\ 'bar':     '',\n    \\ 'fin':     0\n  \\ }\n\n  call s:prepare(1)\n  call append(0, ['', ''])\n  normal! 2G\n  silent! redraw\n\n  \" Set remote name, overriding a possible user git config's clone.defaultRemoteName\n  let s:clone_opt = ['--origin', 'origin']\n  if get(g:, 'plug_shallow', 1)\n    call extend(s:clone_opt, ['--depth', '1'])\n    if s:git_version_requirement(1, 7, 10)\n      call add(s:clone_opt, '--no-single-branch')\n    endif\n  endif\n\n  if has('win32unix') || has('wsl')\n    call extend(s:clone_opt, ['-c', 'core.eol=lf', '-c', 'core.autocrlf=input'])\n  endif\n\n  let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : ''\n\n  \" Python version requirement (>= 2.7)\n  if python && !has('python3') && !ruby && !use_job && s:update.threads > 1\n    redir => pyv\n    silent python import platform; print platform.python_version()\n    redir END\n    let python = s:version_requirement(\n          \\ map(split(split(pyv)[0], '\\.'), 'str2nr(v:val)'), [2, 6])\n  endif\n\n  if (python || ruby) && s:update.threads > 1\n    try\n      let imd = &imd\n      if s:mac_gui\n        set noimd\n      endif\n      if ruby\n        call s:update_ruby()\n      else\n        call s:update_python()\n      endif\n    catch\n      let lines = getline(4, '$')\n      let printed = {}\n      silent! 4,$d _\n      for line in lines\n        let name = s:extract_name(line, '.', '')\n        if empty(name) || !has_key(printed, name)\n          call append('$', line)\n          if !empty(name)\n            let printed[name] = 1\n            if line[0] == 'x' && index(s:update.errors, name) < 0\n              call add(s:update.errors, name)\n            end\n          endif\n        endif\n      endfor\n    finally\n      let &imd = imd\n      call s:update_finish()\n    endtry\n  else\n    call s:update_vim()\n    while use_job && sync\n      sleep 100m\n      if s:update.fin\n        break\n      endif\n    endwhile\n  endif\nendfunction\n\nfunction! s:log4(name, msg)\n  call setline(4, printf('- %s (%s)', a:msg, a:name))\n  redraw\nendfunction\n\nfunction! s:update_finish()\n  if exists('s:git_terminal_prompt')\n    let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt\n  endif\n  if s:switch_in()\n    call append(3, '- Updating ...') | 4\n    for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))'))\n      let [pos, _] = s:logpos(name)\n      if !pos\n        continue\n      endif\n      let out = ''\n      let error = 0\n      if has_key(spec, 'commit')\n        call s:log4(name, 'Checking out '.spec.commit)\n        let [out, error] = s:checkout(spec)\n      elseif has_key(spec, 'tag')\n        let tag = spec.tag\n        if tag =~ '\\*'\n          let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir))\n          if !s:shell_error && !empty(tags)\n            let tag = tags[0]\n            call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag))\n            call append(3, '')\n          endif\n        endif\n        call s:log4(name, 'Checking out '.tag)\n        let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)\n        let error = s:shell_error\n      endif\n      if !error && filereadable(spec.dir.'/.gitmodules') &&\n            \\ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir))\n        call s:log4(name, 'Updating submodules. This may take a while.')\n        let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir)\n        let error = v:shell_error\n      endif\n      let msg = s:format_message(error ? 'x': '-', name, out)\n      if error\n        call add(s:update.errors, name)\n        call s:regress_bar()\n        silent execute pos 'd _'\n        call append(4, msg) | 4\n      elseif !empty(out)\n        call setline(pos, msg[0])\n      endif\n      redraw\n    endfor\n    silent 4 d _\n    try\n      call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, \"do\")'))\n    catch\n      call s:warn('echom', v:exception)\n      call s:warn('echo', '')\n      return\n    endtry\n    call s:finish(s:update.pull)\n    call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.')\n    call s:switch_out('normal! gg')\n  endif\nendfunction\n\nfunction! s:mark_aborted(name, message)\n  let attrs = { 'running': 0, 'error': 1, 'abort': 1, 'lines': [a:message] }\n  let s:jobs[a:name] = extend(get(s:jobs, a:name, {}), attrs)\nendfunction\n\nfunction! s:job_abort(cancel)\n  if (!s:nvim && !s:vim8) || !exists('s:jobs')\n    return\n  endif\n\n  for [name, j] in items(s:jobs)\n    if s:nvim\n      silent! call jobstop(j.jobid)\n    elseif s:vim8\n      silent! call job_stop(j.jobid)\n    endif\n    if j.new\n      call s:rm_rf(g:plugs[name].dir)\n    endif\n    if a:cancel\n      call s:mark_aborted(name, 'Aborted')\n    endif\n  endfor\n\n  if a:cancel\n    for todo in values(s:update.todo)\n      let todo.abort = 1\n    endfor\n  else\n    let s:jobs = {}\n  endif\nendfunction\n\nfunction! s:last_non_empty_line(lines)\n  let len = len(a:lines)\n  for idx in range(len)\n    let line = a:lines[len-idx-1]\n    if !empty(line)\n      return line\n    endif\n  endfor\n  return ''\nendfunction\n\nfunction! s:bullet_for(job, ...)\n  if a:job.running\n    return a:job.new ? '+' : '*'\n  endif\n  if get(a:job, 'abort', 0)\n    return '~'\n  endif\n  return a:job.error ? 'x' : get(a:000, 0, '-')\nendfunction\n\nfunction! s:job_out_cb(self, data) abort\n  let self = a:self\n  let data = remove(self.lines, -1) . a:data\n  let lines = map(split(data, \"\\n\", 1), 'split(v:val, \"\\r\", 1)[-1]')\n  call extend(self.lines, lines)\n  \" To reduce the number of buffer updates\n  let self.tick = get(self, 'tick', -1) + 1\n  if !self.running || self.tick % len(s:jobs) == 0\n    let result = self.error ? join(self.lines, \"\\n\") : s:last_non_empty_line(self.lines)\n    if len(result)\n      call s:log(s:bullet_for(self), self.name, result)\n    endif\n  endif\nendfunction\n\nfunction! s:job_exit_cb(self, data) abort\n  let a:self.running = 0\n  let a:self.error = a:data != 0\n  call s:reap(a:self.name)\n  call s:tick()\nendfunction\n\nfunction! s:job_cb(fn, job, ch, data)\n  if !s:plug_window_exists() \" plug window closed\n    return s:job_abort(0)\n  endif\n  call call(a:fn, [a:job, a:data])\nendfunction\n\nfunction! s:nvim_cb(job_id, data, event) dict abort\n  return (a:event == 'stdout' || a:event == 'stderr') ?\n    \\ s:job_cb('s:job_out_cb',  self, 0, join(a:data, \"\\n\")) :\n    \\ s:job_cb('s:job_exit_cb', self, 0, a:data)\nendfunction\n\nfunction! s:spawn(name, spec, queue, opts)\n  let job = { 'name': a:name, 'spec': a:spec, 'running': 1, 'error': 0, 'lines': [''],\n            \\ 'new': get(a:opts, 'new', 0), 'queue': copy(a:queue) }\n  let Item = remove(job.queue, 0)\n  let argv = type(Item) == s:TYPE.funcref ? call(Item, [a:spec]) : Item\n  let s:jobs[a:name] = job\n\n  if s:nvim\n    if has_key(a:opts, 'dir')\n      let job.cwd = a:opts.dir\n    endif\n    call extend(job, {\n    \\ 'on_stdout': function('s:nvim_cb'),\n    \\ 'on_stderr': function('s:nvim_cb'),\n    \\ 'on_exit':   function('s:nvim_cb'),\n    \\ })\n    let jid = s:plug_call('jobstart', argv, job)\n    if jid > 0\n      let job.jobid = jid\n    else\n      let job.running = 0\n      let job.error   = 1\n      let job.lines   = [jid < 0 ? argv[0].' is not executable' :\n            \\ 'Invalid arguments (or job table is full)']\n    endif\n  elseif s:vim8\n    let cmd = join(map(copy(argv), 'plug#shellescape(v:val, {\"script\": 0})'))\n    if has_key(a:opts, 'dir')\n      let cmd = s:with_cd(cmd, a:opts.dir, 0)\n    endif\n    let argv = s:is_win ? ['cmd', '/s', '/c', '\"'.cmd.'\"'] : ['sh', '-c', cmd]\n    let jid = job_start(s:is_win ? join(argv, ' ') : argv, {\n    \\ 'out_cb':   function('s:job_cb', ['s:job_out_cb',  job]),\n    \\ 'err_cb':   function('s:job_cb', ['s:job_out_cb',  job]),\n    \\ 'exit_cb':  function('s:job_cb', ['s:job_exit_cb', job]),\n    \\ 'err_mode': 'raw',\n    \\ 'out_mode': 'raw'\n    \\})\n    if job_status(jid) == 'run'\n      let job.jobid = jid\n    else\n      let job.running = 0\n      let job.error   = 1\n      let job.lines   = ['Failed to start job']\n    endif\n  else\n    let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [argv, a:opts.dir] : [argv]))\n    let job.error = s:shell_error != 0\n    let job.running = 0\n  endif\nendfunction\n\nfunction! s:reap(name)\n  let job = remove(s:jobs, a:name)\n  if job.error\n    call add(s:update.errors, a:name)\n  elseif get(job, 'new', 0)\n    let s:update.new[a:name] = 1\n  endif\n\n  let more = len(get(job, 'queue', []))\n  let result = job.error ? join(job.lines, \"\\n\") : s:last_non_empty_line(job.lines)\n  if len(result)\n    call s:log(s:bullet_for(job), a:name, result)\n  endif\n\n  if !job.error && more\n    let job.spec.queue = job.queue\n    let s:update.todo[a:name] = job.spec\n  else\n    let s:update.bar .= s:bullet_for(job, '=')\n    call s:bar()\n  endif\nendfunction\n\nfunction! s:bar()\n  if s:switch_in()\n    let total = len(s:update.all)\n    call setline(1, (s:update.pull ? 'Updating' : 'Installing').\n          \\ ' plugins ('.len(s:update.bar).'/'.total.')')\n    call s:progress_bar(2, s:update.bar, total)\n    call s:switch_out()\n  endif\nendfunction\n\nfunction! s:logpos(name)\n  let max = line('$')\n  for i in range(4, max > 4 ? max : 4)\n    if getline(i) =~# '^[-+x*] '.a:name.':'\n      for j in range(i + 1, max > 5 ? max : 5)\n        if getline(j) !~ '^ '\n          return [i, j - 1]\n        endif\n      endfor\n      return [i, i]\n    endif\n  endfor\n  return [0, 0]\nendfunction\n\nfunction! s:log(bullet, name, lines)\n  if s:switch_in()\n    let [b, e] = s:logpos(a:name)\n    if b > 0\n      silent execute printf('%d,%d d _', b, e)\n      if b > winheight('.')\n        let b = 4\n      endif\n    else\n      let b = 4\n    endif\n    \" FIXME For some reason, nomodifiable is set after :d in vim8\n    setlocal modifiable\n    call append(b - 1, s:format_message(a:bullet, a:name, a:lines))\n    call s:switch_out()\n  endif\nendfunction\n\nfunction! s:update_vim()\n  let s:jobs = {}\n\n  call s:bar()\n  call s:tick()\nendfunction\n\nfunction! s:checkout_command(spec)\n  let a:spec.branch = s:git_origin_branch(a:spec)\n  return ['git', 'checkout', '-q', a:spec.branch, '--']\nendfunction\n\nfunction! s:merge_command(spec)\n  let a:spec.branch = s:git_origin_branch(a:spec)\n  return ['git', 'merge', '--ff-only', 'origin/'.a:spec.branch]\nendfunction\n\nfunction! s:tick()\n  let pull = s:update.pull\n  let prog = s:progress_opt(s:nvim || s:vim8)\nwhile 1 \" Without TCO, Vim stack is bound to explode\n  if empty(s:update.todo)\n    if empty(s:jobs) && !s:update.fin\n      call s:update_finish()\n      let s:update.fin = 1\n    endif\n    return\n  endif\n\n  let name = keys(s:update.todo)[0]\n  let spec = remove(s:update.todo, name)\n  if get(spec, 'abort', 0)\n    call s:mark_aborted(name, 'Skipped')\n    call s:reap(name)\n    continue\n  endif\n\n  let queue = get(spec, 'queue', [])\n  let new = empty(globpath(spec.dir, '.git', 1))\n\n  if empty(queue)\n    call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...')\n    redraw\n  endif\n\n  let has_tag = has_key(spec, 'tag')\n  if len(queue)\n    call s:spawn(name, spec, queue, { 'dir': spec.dir })\n  elseif !new\n    let [error, _] = s:git_validate(spec, 0)\n    if empty(error)\n      if pull\n        let cmd = s:disable_credential_helper() ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']\n        if has_tag && !empty(globpath(spec.dir, '.git/shallow'))\n          call extend(cmd, ['--depth', '99999999'])\n        endif\n        if !empty(prog)\n          call add(cmd, prog)\n        endif\n        let queue = [cmd, split('git remote set-head origin -a')]\n        if !has_tag && !has_key(spec, 'commit')\n          call extend(queue, [function('s:checkout_command'), function('s:merge_command')])\n        endif\n        call s:spawn(name, spec, queue, { 'dir': spec.dir })\n      else\n        let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 }\n      endif\n    else\n      let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 }\n    endif\n  else\n    let cmd = ['git', 'clone']\n    if !has_tag\n      call extend(cmd, s:clone_opt)\n    endif\n    if !empty(prog)\n      call add(cmd, prog)\n    endif\n    call s:spawn(name, spec, [extend(cmd, [spec.uri, s:trim(spec.dir)]), function('s:checkout_command'), function('s:merge_command')], { 'new': 1 })\n  endif\n\n  if !s:jobs[name].running\n    call s:reap(name)\n  endif\n  if len(s:jobs) >= s:update.threads\n    break\n  endif\nendwhile\nendfunction\n\nfunction! s:update_python()\nlet py_exe = has('python') ? 'python' : 'python3'\nexecute py_exe \"<< EOF\"\nimport datetime\nimport functools\nimport os\ntry:\n  import queue\nexcept ImportError:\n  import Queue as queue\nimport random\nimport re\nimport shutil\nimport signal\nimport subprocess\nimport tempfile\nimport threading as thr\nimport time\nimport traceback\nimport vim\n\nG_NVIM = vim.eval(\"has('nvim')\") == '1'\nG_PULL = vim.eval('s:update.pull') == '1'\nG_RETRIES = int(vim.eval('get(g:, \"plug_retries\", 2)')) + 1\nG_TIMEOUT = int(vim.eval('get(g:, \"plug_timeout\", 60)'))\nG_CLONE_OPT = ' '.join(vim.eval('s:clone_opt'))\nG_PROGRESS = vim.eval('s:progress_opt(1)')\nG_LOG_PROB = 1.0 / int(vim.eval('s:update.threads'))\nG_STOP = thr.Event()\nG_IS_WIN = vim.eval('s:is_win') == '1'\n\nclass PlugError(Exception):\n  def __init__(self, msg):\n    self.msg = msg\nclass CmdTimedOut(PlugError):\n  pass\nclass CmdFailed(PlugError):\n  pass\nclass InvalidURI(PlugError):\n  pass\nclass Action(object):\n  INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-']\n\nclass Buffer(object):\n  def __init__(self, lock, num_plugs, is_pull):\n    self.bar = ''\n    self.event = 'Updating' if is_pull else 'Installing'\n    self.lock = lock\n    self.maxy = int(vim.eval('winheight(\".\")'))\n    self.num_plugs = num_plugs\n\n  def __where(self, name):\n    \"\"\" Find first line with name in current buffer. Return line num. \"\"\"\n    found, lnum = False, 0\n    matcher = re.compile('^[-+x*] {0}:'.format(name))\n    for line in vim.current.buffer:\n      if matcher.search(line) is not None:\n        found = True\n        break\n      lnum += 1\n\n    if not found:\n      lnum = -1\n    return lnum\n\n  def header(self):\n    curbuf = vim.current.buffer\n    curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs)\n\n    num_spaces = self.num_plugs - len(self.bar)\n    curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ')\n\n    with self.lock:\n      vim.command('normal! 2G')\n      vim.command('redraw')\n\n  def write(self, action, name, lines):\n    first, rest = lines[0], lines[1:]\n    msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)]\n    msg.extend(['    ' + line for line in rest])\n\n    try:\n      if action == Action.ERROR:\n        self.bar += 'x'\n        vim.command(\"call add(s:update.errors, '{0}')\".format(name))\n      elif action == Action.DONE:\n        self.bar += '='\n\n      curbuf = vim.current.buffer\n      lnum = self.__where(name)\n      if lnum != -1: # Found matching line num\n        del curbuf[lnum]\n        if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]):\n          lnum = 3\n      else:\n        lnum = 3\n      curbuf.append(msg, lnum)\n\n      self.header()\n    except vim.error:\n      pass\n\nclass Command(object):\n  CD = 'cd /d' if G_IS_WIN else 'cd'\n\n  def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None):\n    self.cmd = cmd\n    if cmd_dir:\n      self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd)\n    self.timeout = timeout\n    self.callback = cb if cb else (lambda msg: None)\n    self.clean = clean if clean else (lambda: None)\n    self.proc = None\n\n  @property\n  def alive(self):\n    \"\"\" Returns true only if command still running. \"\"\"\n    return self.proc and self.proc.poll() is None\n\n  def execute(self, ntries=3):\n    \"\"\" Execute the command with ntries if CmdTimedOut.\n        Returns the output of the command if no Exception.\n    \"\"\"\n    attempt, finished, limit = 0, False, self.timeout\n\n    while not finished:\n      try:\n        attempt += 1\n        result = self.try_command()\n        finished = True\n        return result\n      except CmdTimedOut:\n        if attempt != ntries:\n          self.notify_retry()\n          self.timeout += limit\n        else:\n          raise\n\n  def notify_retry(self):\n    \"\"\" Retry required for command, notify user. \"\"\"\n    for count in range(3, 0, -1):\n      if G_STOP.is_set():\n        raise KeyboardInterrupt\n      msg = 'Timeout. Will retry in {0} second{1} ...'.format(\n            count, 's' if count != 1 else '')\n      self.callback([msg])\n      time.sleep(1)\n    self.callback(['Retrying ...'])\n\n  def try_command(self):\n    \"\"\" Execute a cmd & poll for callback. Returns list of output.\n        Raises CmdFailed   -> return code for Popen isn't 0\n        Raises CmdTimedOut -> command exceeded timeout without new output\n    \"\"\"\n    first_line = True\n\n    try:\n      tfile = tempfile.NamedTemporaryFile(mode='w+b')\n      preexec_fn = not G_IS_WIN and os.setsid or None\n      self.proc = subprocess.Popen(self.cmd, stdout=tfile,\n                                   stderr=subprocess.STDOUT,\n                                   stdin=subprocess.PIPE, shell=True,\n                                   preexec_fn=preexec_fn)\n      thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,))\n      thrd.start()\n\n      thread_not_started = True\n      while thread_not_started:\n        try:\n          thrd.join(0.1)\n          thread_not_started = False\n        except RuntimeError:\n          pass\n\n      while self.alive:\n        if G_STOP.is_set():\n          raise KeyboardInterrupt\n\n        if first_line or random.random() < G_LOG_PROB:\n          first_line = False\n          line = '' if G_IS_WIN else nonblock_read(tfile.name)\n          if line:\n            self.callback([line])\n\n        time_diff = time.time() - os.path.getmtime(tfile.name)\n        if time_diff > self.timeout:\n          raise CmdTimedOut(['Timeout!'])\n\n        thrd.join(0.5)\n\n      tfile.seek(0)\n      result = [line.decode('utf-8', 'replace').rstrip() for line in tfile]\n\n      if self.proc.returncode != 0:\n        raise CmdFailed([''] + result)\n\n      return result\n    except:\n      self.terminate()\n      raise\n\n  def terminate(self):\n    \"\"\" Terminate process and cleanup. \"\"\"\n    if self.alive:\n      if G_IS_WIN:\n        os.kill(self.proc.pid, signal.SIGINT)\n      else:\n        os.killpg(self.proc.pid, signal.SIGTERM)\n    self.clean()\n\nclass Plugin(object):\n  def __init__(self, name, args, buf_q, lock):\n    self.name = name\n    self.args = args\n    self.buf_q = buf_q\n    self.lock = lock\n    self.tag = args.get('tag', 0)\n\n  def manage(self):\n    try:\n      if os.path.exists(self.args['dir']):\n        self.update()\n      else:\n        self.install()\n        with self.lock:\n          thread_vim_command(\"let s:update.new['{0}'] = 1\".format(self.name))\n    except PlugError as exc:\n      self.write(Action.ERROR, self.name, exc.msg)\n    except KeyboardInterrupt:\n      G_STOP.set()\n      self.write(Action.ERROR, self.name, ['Interrupted!'])\n    except:\n      # Any exception except those above print stack trace\n      msg = 'Trace:\\n{0}'.format(traceback.format_exc().rstrip())\n      self.write(Action.ERROR, self.name, msg.split('\\n'))\n      raise\n\n  def install(self):\n    target = self.args['dir']\n    if target[-1] == '\\\\':\n      target = target[0:-1]\n\n    def clean(target):\n      def _clean():\n        try:\n          shutil.rmtree(target)\n        except OSError:\n          pass\n      return _clean\n\n    self.write(Action.INSTALL, self.name, ['Installing ...'])\n    callback = functools.partial(self.write, Action.INSTALL, self.name)\n    cmd = 'git clone {0} {1} {2} {3} 2>&1'.format(\n          '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'],\n          esc(target))\n    com = Command(cmd, None, G_TIMEOUT, callback, clean(target))\n    result = com.execute(G_RETRIES)\n    self.write(Action.DONE, self.name, result[-1:])\n\n  def repo_uri(self):\n    cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url'\n    command = Command(cmd, self.args['dir'], G_TIMEOUT,)\n    result = command.execute(G_RETRIES)\n    return result[-1]\n\n  def update(self):\n    actual_uri = self.repo_uri()\n    expect_uri = self.args['uri']\n    regex = re.compile(r'^(?:\\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\\.git)?/?$')\n    ma = regex.match(actual_uri)\n    mb = regex.match(expect_uri)\n    if ma is None or mb is None or ma.groups() != mb.groups():\n      msg = ['',\n             'Invalid URI: {0}'.format(actual_uri),\n             'Expected     {0}'.format(expect_uri),\n             'PlugClean required.']\n      raise InvalidURI(msg)\n\n    if G_PULL:\n      self.write(Action.UPDATE, self.name, ['Updating ...'])\n      callback = functools.partial(self.write, Action.UPDATE, self.name)\n      fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else ''\n      cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS)\n      com = Command(cmd, self.args['dir'], G_TIMEOUT, callback)\n      result = com.execute(G_RETRIES)\n      self.write(Action.DONE, self.name, result[-1:])\n    else:\n      self.write(Action.DONE, self.name, ['Already installed'])\n\n  def write(self, action, name, msg):\n    self.buf_q.put((action, name, msg))\n\nclass PlugThread(thr.Thread):\n  def __init__(self, tname, args):\n    super(PlugThread, self).__init__()\n    self.tname = tname\n    self.args = args\n\n  def run(self):\n    thr.current_thread().name = self.tname\n    buf_q, work_q, lock = self.args\n\n    try:\n      while not G_STOP.is_set():\n        name, args = work_q.get_nowait()\n        plug = Plugin(name, args, buf_q, lock)\n        plug.manage()\n        work_q.task_done()\n    except queue.Empty:\n      pass\n\nclass RefreshThread(thr.Thread):\n  def __init__(self, lock):\n    super(RefreshThread, self).__init__()\n    self.lock = lock\n    self.running = True\n\n  def run(self):\n    while self.running:\n      with self.lock:\n        thread_vim_command('noautocmd normal! a')\n      time.sleep(0.33)\n\n  def stop(self):\n    self.running = False\n\nif G_NVIM:\n  def thread_vim_command(cmd):\n    vim.session.threadsafe_call(lambda: vim.command(cmd))\nelse:\n  def thread_vim_command(cmd):\n    vim.command(cmd)\n\ndef esc(name):\n  return '\"' + name.replace('\"', '\\\"') + '\"'\n\ndef nonblock_read(fname):\n  \"\"\" Read a file with nonblock flag. Return the last line. \"\"\"\n  fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK)\n  buf = os.read(fread, 100000).decode('utf-8', 'replace')\n  os.close(fread)\n\n  line = buf.rstrip('\\r\\n')\n  left = max(line.rfind('\\r'), line.rfind('\\n'))\n  if left != -1:\n    left += 1\n    line = line[left:]\n\n  return line\n\ndef main():\n  thr.current_thread().name = 'main'\n  nthreads = int(vim.eval('s:update.threads'))\n  plugs = vim.eval('s:update.todo')\n  mac_gui = vim.eval('s:mac_gui') == '1'\n\n  lock = thr.Lock()\n  buf = Buffer(lock, len(plugs), G_PULL)\n  buf_q, work_q = queue.Queue(), queue.Queue()\n  for work in plugs.items():\n    work_q.put(work)\n\n  start_cnt = thr.active_count()\n  for num in range(nthreads):\n    tname = 'PlugT-{0:02}'.format(num)\n    thread = PlugThread(tname, (buf_q, work_q, lock))\n    thread.start()\n  if mac_gui:\n    rthread = RefreshThread(lock)\n    rthread.start()\n\n  while not buf_q.empty() or thr.active_count() != start_cnt:\n    try:\n      action, name, msg = buf_q.get(True, 0.25)\n      buf.write(action, name, ['OK'] if not msg else msg)\n      buf_q.task_done()\n    except queue.Empty:\n      pass\n    except KeyboardInterrupt:\n      G_STOP.set()\n\n  if mac_gui:\n    rthread.stop()\n    rthread.join()\n\nmain()\nEOF\nendfunction\n\nfunction! s:update_ruby()\n  ruby << EOF\n  module PlugStream\n    SEP = [\"\\r\", \"\\n\", nil]\n    def get_line\n      buffer = ''\n      loop do\n        char = readchar rescue return\n        if SEP.include? char.chr\n          buffer << $/\n          break\n        else\n          buffer << char\n        end\n      end\n      buffer\n    end\n  end unless defined?(PlugStream)\n\n  def esc arg\n    %[\"#{arg.gsub('\"', '\\\"')}\"]\n  end\n\n  def killall pid\n    pids = [pid]\n    if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM\n      pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil }\n    else\n      unless `which pgrep 2> /dev/null`.empty?\n        children = pids\n        until children.empty?\n          children = children.map { |pid|\n            `pgrep -P #{pid}`.lines.map { |l| l.chomp }\n          }.flatten\n          pids += children\n        end\n      end\n      pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }\n    end\n  end\n\n  def compare_git_uri a, b\n    regex = %r{^(?:\\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\\.git)?/?$}\n    regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1)\n  end\n\n  require 'thread'\n  require 'fileutils'\n  require 'timeout'\n  running = true\n  iswin = VIM::evaluate('s:is_win').to_i == 1\n  pull  = VIM::evaluate('s:update.pull').to_i == 1\n  base  = VIM::evaluate('g:plug_home')\n  all   = VIM::evaluate('s:update.todo')\n  limit = VIM::evaluate('get(g:, \"plug_timeout\", 60)')\n  tries = VIM::evaluate('get(g:, \"plug_retries\", 2)') + 1\n  nthr  = VIM::evaluate('s:update.threads').to_i\n  maxy  = VIM::evaluate('winheight(\".\")').to_i\n  vim7  = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/\n  cd    = iswin ? 'cd /d' : 'cd'\n  tot   = VIM::evaluate('len(s:update.todo)') || 0\n  bar   = ''\n  skip  = 'Already installed'\n  mtx   = Mutex.new\n  take1 = proc { mtx.synchronize { running && all.shift } }\n  logh  = proc {\n    cnt = bar.length\n    $curbuf[1] = \"#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})\"\n    $curbuf[2] = '[' + bar.ljust(tot) + ']'\n    VIM::command('normal! 2G')\n    VIM::command('redraw')\n  }\n  where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }\n  log   = proc { |name, result, type|\n    mtx.synchronize do\n      ing  = ![true, false].include?(type)\n      bar += type ? '=' : 'x' unless ing\n      b = case type\n          when :install  then '+' when :update then '*'\n          when true, nil then '-' else\n            VIM::command(\"call add(s:update.errors, '#{name}')\")\n            'x'\n          end\n      result =\n        if type || type.nil?\n          [\"#{b} #{name}: #{result.lines.to_a.last || 'OK'}\"]\n        elsif result =~ /^Interrupted|^Timeout/\n          [\"#{b} #{name}: #{result}\"]\n        else\n          [\"#{b} #{name}\"] + result.lines.map { |l| \"    \" << l }\n        end\n      if lnum = where.call(name)\n        $curbuf.delete lnum\n        lnum = 4 if ing && lnum > maxy\n      end\n      result.each_with_index do |line, offset|\n        $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\\e\\[./, '').chomp)\n      end\n      logh.call\n    end\n  }\n  bt = proc { |cmd, name, type, cleanup|\n    tried = timeout = 0\n    begin\n      tried += 1\n      timeout += limit\n      fd = nil\n      data = ''\n      if iswin\n        Timeout::timeout(timeout) do\n          tmp = VIM::evaluate('tempname()')\n          system(\"(#{cmd}) > #{tmp}\")\n          data = File.read(tmp).chomp\n          File.unlink tmp rescue nil\n        end\n      else\n        fd = IO.popen(cmd).extend(PlugStream)\n        first_line = true\n        log_prob = 1.0 / nthr\n        while line = Timeout::timeout(timeout) { fd.get_line }\n          data << line\n          log.call name, line.chomp, type if name && (first_line || rand < log_prob)\n          first_line = false\n        end\n        fd.close\n      end\n      [$? == 0, data.chomp]\n    rescue Timeout::Error, Interrupt => e\n      if fd && !fd.closed?\n        killall fd.pid\n        fd.close\n      end\n      cleanup.call if cleanup\n      if e.is_a?(Timeout::Error) && tried < tries\n        3.downto(1) do |countdown|\n          s = countdown > 1 ? 's' : ''\n          log.call name, \"Timeout. Will retry in #{countdown} second#{s} ...\", type\n          sleep 1\n        end\n        log.call name, 'Retrying ...', type\n        retry\n      end\n      [false, e.is_a?(Interrupt) ? \"Interrupted!\" : \"Timeout!\"]\n    end\n  }\n  main = Thread.current\n  threads = []\n  watcher = Thread.new {\n    if vim7\n      while VIM::evaluate('getchar(1)')\n        sleep 0.1\n      end\n    else\n      require 'io/console' # >= Ruby 1.9\n      nil until IO.console.getch == 3.chr\n    end\n    mtx.synchronize do\n      running = false\n      threads.each { |t| t.raise Interrupt } unless vim7\n    end\n    threads.each { |t| t.join rescue nil }\n    main.kill\n  }\n  refresh = Thread.new {\n    while true\n      mtx.synchronize do\n        break unless running\n        VIM::command('noautocmd normal! a')\n      end\n      sleep 0.2\n    end\n  } if VIM::evaluate('s:mac_gui') == 1\n\n  clone_opt = VIM::evaluate('s:clone_opt').join(' ')\n  progress = VIM::evaluate('s:progress_opt(1)')\n  nthr.times do\n    mtx.synchronize do\n      threads << Thread.new {\n        while pair = take1.call\n          name = pair.first\n          dir, uri, tag = pair.last.values_at *%w[dir uri tag]\n          exists = File.directory? dir\n          ok, result =\n            if exists\n              chdir = \"#{cd} #{iswin ? dir : esc(dir)}\"\n              ret, data = bt.call \"#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url\", nil, nil, nil\n              current_uri = data.lines.to_a.last\n              if !ret\n                if data =~ /^Interrupted|^Timeout/\n                  [false, data]\n                else\n                  [false, [data.chomp, \"PlugClean required.\"].join($/)]\n                end\n              elsif !compare_git_uri(current_uri, uri)\n                [false, [\"Invalid URI: #{current_uri}\",\n                         \"Expected:    #{uri}\",\n                         \"PlugClean required.\"].join($/)]\n              else\n                if pull\n                  log.call name, 'Updating ...', :update\n                  fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : ''\n                  bt.call \"#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1\", name, :update, nil\n                else\n                  [true, skip]\n                end\n              end\n            else\n              d = esc dir.sub(%r{[\\\\/]+$}, '')\n              log.call name, 'Installing ...', :install\n              bt.call \"git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1\", name, :install, proc {\n                FileUtils.rm_rf dir\n              }\n            end\n          mtx.synchronize { VIM::command(\"let s:update.new['#{name}'] = 1\") } if !exists && ok\n          log.call name, result, ok\n        end\n      } if running\n    end\n  end\n  threads.each { |t| t.join rescue nil }\n  logh.call\n  refresh.kill if refresh\n  watcher.kill\nEOF\nendfunction\n\nfunction! s:shellesc_cmd(arg, script)\n  let escaped = substitute('\"'.a:arg.'\"', '[&|<>()@^!\"]', '^&', 'g')\n  return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g')\nendfunction\n\nfunction! s:shellesc_ps1(arg)\n  return \"'\".substitute(escape(a:arg, '\\\"'), \"'\", \"''\", 'g').\"'\"\nendfunction\n\nfunction! s:shellesc_sh(arg)\n  return \"'\".substitute(a:arg, \"'\", \"'\\\\\\\\''\", 'g').\"'\"\nendfunction\n\n\" Escape the shell argument based on the shell.\n\" Vim and Neovim's shellescape() are insufficient.\n\" 1. shellslash determines whether to use single/double quotes.\n\"    Double-quote escaping is fragile for cmd.exe.\n\" 2. It does not work for powershell.\n\" 3. It does not work for *sh shells if the command is executed\n\"    via cmd.exe (ie. cmd.exe /c sh -c command command_args)\n\" 4. It does not support batchfile syntax.\n\"\n\" Accepts an optional dictionary with the following keys:\n\" - shell: same as Vim/Neovim 'shell' option.\n\"          If unset, fallback to 'cmd.exe' on Windows or 'sh'.\n\" - script: If truthy and shell is cmd.exe, escape for batchfile syntax.\nfunction! plug#shellescape(arg, ...)\n  if a:arg =~# '^[A-Za-z0-9_/:.-]\\+$'\n    return a:arg\n  endif\n  let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}\n  let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh')\n  let script = get(opts, 'script', 1)\n  if shell =~# 'cmd\\(\\.exe\\)\\?$'\n    return s:shellesc_cmd(a:arg, script)\n  elseif s:is_powershell(shell)\n    return s:shellesc_ps1(a:arg)\n  endif\n  return s:shellesc_sh(a:arg)\nendfunction\n\nfunction! s:glob_dir(path)\n  return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)')\nendfunction\n\nfunction! s:progress_bar(line, bar, total)\n  call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')\nendfunction\n\nfunction! s:compare_git_uri(a, b)\n  \" See `git help clone'\n  \" https:// [user@] github.com[:port] / junegunn/vim-plug [.git]\n  \"          [git@]  github.com[:port] : junegunn/vim-plug [.git]\n  \" file://                            / junegunn/vim-plug        [/]\n  \"                                    / junegunn/vim-plug        [/]\n  let pat = '^\\%(\\w\\+://\\)\\='.'\\%([^@/]*@\\)\\='.'\\([^:/]*\\%(:[0-9]*\\)\\=\\)'.'[:/]'.'\\(.\\{-}\\)'.'\\%(\\.git\\)\\=/\\?$'\n  let ma = matchlist(a:a, pat)\n  let mb = matchlist(a:b, pat)\n  return ma[1:2] ==# mb[1:2]\nendfunction\n\nfunction! s:format_message(bullet, name, message)\n  if a:bullet != 'x'\n    return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))]\n  else\n    let lines = map(s:lines(a:message), '\"    \".v:val')\n    return extend([printf('x %s:', a:name)], lines)\n  endif\nendfunction\n\nfunction! s:with_cd(cmd, dir, ...)\n  let script = a:0 > 0 ? a:1 : 1\n  let pwsh = s:is_powershell(&shell)\n  let cd = s:is_win && !pwsh ? 'cd /d' : 'cd'\n  let sep = pwsh ? ';' : '&&'\n  return printf('%s %s %s %s', cd, plug#shellescape(a:dir, {'script': script, 'shell': &shell}), sep, a:cmd)\nendfunction\n\nfunction! s:system_job(cmd) abort\n  let tmp = tempname()\n  let job = job_start(['/bin/sh', '-c', a:cmd], {\n  \\ 'out_io': 'file',\n  \\ 'out_name': tmp,\n  \\ 'err_io': 'out',\n  \\})\n  while job_status(job) ==# 'run'\n    sleep 1m\n  endwhile\n  let s:shell_error = job_info(job).exitval\n  let result = filereadable(tmp) ? join(readfile(tmp, 'b'), \"\\n\") : ''\n  silent! call delete(tmp)\n  return result\nendfunction\n\nfunction! s:system(cmd, ...)\n  let batchfile = ''\n  try\n    let [sh, shellcmdflag, shrd] = s:chsh(1)\n    if type(a:cmd) == s:TYPE.list\n      \" Neovim's system() supports list argument to bypass the shell\n      \" but it cannot set the working directory for the command.\n      \" Assume that the command does not rely on the shell.\n      if has('nvim') && a:0 == 0\n        let ret = system(a:cmd)\n        let s:shell_error = v:shell_error\n        return ret\n      endif\n      let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {\"shell\": &shell, \"script\": 0})'))\n      if s:is_powershell(&shell)\n        let cmd = '& ' . cmd\n      endif\n    else\n      let cmd = a:cmd\n    endif\n    if a:0 > 0\n      let cmd = s:with_cd(cmd, a:1, type(a:cmd) != s:TYPE.list)\n    endif\n    if s:is_win && type(a:cmd) != s:TYPE.list\n      let [batchfile, cmd] = s:batchfile(cmd)\n    endif\n    if s:vim8 && has('gui_running') && !s:is_win\n      return s:system_job(cmd)\n    endif\n    let ret = system(cmd)\n    let s:shell_error = v:shell_error\n    return ret\n  finally\n    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]\n    if s:is_win && filereadable(batchfile)\n      call delete(batchfile)\n    endif\n  endtry\nendfunction\n\nfunction! s:system_chomp(...)\n  let ret = call('s:system', a:000)\n  return s:shell_error ? '' : substitute(ret, '\\n$', '', '')\nendfunction\n\nfunction! s:git_validate(spec, check_branch)\n  let err = ''\n  if isdirectory(a:spec.dir)\n    let result = [s:git_local_branch(a:spec.dir), s:git_origin_url(a:spec.dir)]\n    let remote = result[-1]\n    if empty(remote)\n      let err = join([remote, 'PlugClean required.'], \"\\n\")\n    elseif !s:compare_git_uri(remote, a:spec.uri)\n      let err = join(['Invalid URI: '.remote,\n                    \\ 'Expected:    '.a:spec.uri,\n                    \\ 'PlugClean required.'], \"\\n\")\n    elseif !a:check_branch\n      return ['', 0]\n    elseif has_key(a:spec, 'commit')\n      let sha = s:git_revision(a:spec.dir)\n      if empty(sha)\n        let err = join(add(result, 'PlugClean required.'), \"\\n\")\n      elseif !s:hash_match(sha, a:spec.commit)\n        let err = join([printf('Invalid HEAD (expected: %s, actual: %s)',\n                              \\ a:spec.commit[:6], sha[:6]),\n                      \\ 'PlugUpdate required.'], \"\\n\")\n      endif\n    elseif has_key(a:spec, 'tag')\n      let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)\n      if a:spec.tag !=# tag && a:spec.tag !~ '\\*'\n        let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',\n              \\ (empty(tag) ? 'N/A' : tag), a:spec.tag)\n      endif\n    elseif a:check_branch\n      let current_branch = result[0]\n      let origin_branch = s:git_origin_branch(a:spec)\n      if origin_branch !=# current_branch\n        let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',\n              \\ current_branch, origin_branch)\n      endif\n      if empty(err)\n        let ahead_behind = split(s:lastline(s:system([\n          \\ 'git', 'rev-list', '--count', '--left-right',\n          \\ printf('HEAD...origin/%s', origin_branch)\n          \\ ], a:spec.dir)), '\\t')\n        if s:shell_error || len(ahead_behind) != 2\n          let err = \"Failed to compare with the origin. The default branch might have changed.\\nPlugClean required.\"\n        else\n          let [ahead, behind] = ahead_behind\n          if ahead && behind\n            \" Only mention PlugClean if diverged, otherwise it's likely to be\n            \" pushable (and probably not that messed up).\n            let err = printf(\n                  \\ \"Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\\n\"\n                  \\ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', origin_branch, ahead, behind)\n          elseif ahead\n            let err = printf(\"Ahead of origin/%s by %d commit(s).\\n\"\n                  \\ .'Cannot update until local changes are pushed.',\n                  \\ origin_branch, ahead)\n          endif\n        endif\n      endif\n    endif\n  else\n    let err = 'Not found'\n  endif\n  return [err, err =~# 'PlugClean']\nendfunction\n\nfunction! s:rm_rf(dir)\n  if isdirectory(a:dir)\n    return s:system(s:is_win\n    \\ ? 'rmdir /S /Q '.plug#shellescape(a:dir)\n    \\ : ['rm', '-rf', a:dir])\n  endif\nendfunction\n\nfunction! s:clean(force)\n  call s:prepare()\n  call append(0, 'Searching for invalid plugins in '.g:plug_home)\n  call append(1, '')\n\n  \" List of valid directories\n  let dirs = []\n  let errs = {}\n  let [cnt, total] = [0, len(g:plugs)]\n  for [name, spec] in items(g:plugs)\n    if !s:is_managed(name) || get(spec, 'frozen', 0)\n      call add(dirs, spec.dir)\n    else\n      let [err, clean] = s:git_validate(spec, 1)\n      if clean\n        let errs[spec.dir] = s:lines(err)[0]\n      else\n        call add(dirs, spec.dir)\n      endif\n    endif\n    let cnt += 1\n    call s:progress_bar(2, repeat('=', cnt), total)\n    normal! 2G\n    redraw\n  endfor\n\n  let allowed = {}\n  for dir in dirs\n    let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1\n    let allowed[dir] = 1\n    for child in s:glob_dir(dir)\n      let allowed[child] = 1\n    endfor\n  endfor\n\n  let todo = []\n  let found = sort(s:glob_dir(g:plug_home))\n  while !empty(found)\n    let f = remove(found, 0)\n    if !has_key(allowed, f) && isdirectory(f)\n      call add(todo, f)\n      call append(line('$'), '- ' . f)\n      if has_key(errs, f)\n        call append(line('$'), '    ' . errs[f])\n      endif\n      let found = filter(found, 'stridx(v:val, f) != 0')\n    end\n  endwhile\n\n  4\n  redraw\n  if empty(todo)\n    call append(line('$'), 'Already clean.')\n  else\n    let s:clean_count = 0\n    call append(3, ['Directories to delete:', ''])\n    redraw!\n    if a:force || s:ask_no_interrupt('Delete all directories?')\n      call s:delete([6, line('$')], 1)\n    else\n      call setline(4, 'Cancelled.')\n      nnoremap <silent> <buffer> d :set opfunc=<sid>delete_op<cr>g@\n      nmap     <silent> <buffer> dd d_\n      xnoremap <silent> <buffer> d :<c-u>call <sid>delete_op(visualmode(), 1)<cr>\n      echo 'Delete the lines (d{motion}) to delete the corresponding directories'\n    endif\n  endif\n  4\n  setlocal nomodifiable\nendfunction\n\nfunction! s:delete_op(type, ...)\n  call s:delete(a:0 ? [line(\"'<\"), line(\"'>\")] : [line(\"'[\"), line(\"']\")], 0)\nendfunction\n\nfunction! s:delete(range, force)\n  let [l1, l2] = a:range\n  let force = a:force\n  let err_count = 0\n  while l1 <= l2\n    let line = getline(l1)\n    if line =~ '^- ' && isdirectory(line[2:])\n      execute l1\n      redraw!\n      let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1)\n      let force = force || answer > 1\n      if answer\n        let err = s:rm_rf(line[2:])\n        setlocal modifiable\n        if empty(err)\n          call setline(l1, '~'.line[1:])\n          let s:clean_count += 1\n        else\n          delete _\n          call append(l1 - 1, s:format_message('x', line[1:], err))\n          let l2 += len(s:lines(err))\n          let err_count += 1\n        endif\n        let msg = printf('Removed %d directories.', s:clean_count)\n        if err_count > 0\n          let msg .= printf(' Failed to remove %d directories.', err_count)\n        endif\n        call setline(4, msg)\n        setlocal nomodifiable\n      endif\n    endif\n    let l1 += 1\n  endwhile\nendfunction\n\nfunction! s:upgrade()\n  echo 'Downloading the latest version of vim-plug'\n  redraw\n  let tmp = s:plug_tempname()\n  let new = tmp . '/plug.vim'\n\n  try\n    let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp])\n    if s:shell_error\n      return s:err('Error upgrading vim-plug: '. out)\n    endif\n\n    if readfile(s:me) ==# readfile(new)\n      echo 'vim-plug is already up-to-date'\n      return 0\n    else\n      call rename(s:me, s:me . '.old')\n      call rename(new, s:me)\n      unlet g:loaded_plug\n      echo 'vim-plug has been upgraded'\n      return 1\n    endif\n  finally\n    silent! call s:rm_rf(tmp)\n  endtry\nendfunction\n\nfunction! s:upgrade_specs()\n  for spec in values(g:plugs)\n    let spec.frozen = get(spec, 'frozen', 0)\n  endfor\nendfunction\n\nfunction! s:status()\n  call s:prepare()\n  call append(0, 'Checking plugins')\n  call append(1, '')\n\n  let ecnt = 0\n  let unloaded = 0\n  let [cnt, total] = [0, len(g:plugs)]\n  for [name, spec] in items(g:plugs)\n    let is_dir = isdirectory(spec.dir)\n    if has_key(spec, 'uri')\n      if is_dir\n        let [err, _] = s:git_validate(spec, 1)\n        let [valid, msg] = [empty(err), empty(err) ? 'OK' : err]\n      else\n        let [valid, msg] = [0, 'Not found. Try PlugInstall.']\n      endif\n    else\n      if is_dir\n        let [valid, msg] = [1, 'OK']\n      else\n        let [valid, msg] = [0, 'Not found.']\n      endif\n    endif\n    let cnt += 1\n    let ecnt += !valid\n    \" `s:loaded` entry can be missing if PlugUpgraded\n    if is_dir && get(s:loaded, name, -1) == 0\n      let unloaded = 1\n      let msg .= ' (not loaded)'\n    endif\n    call s:progress_bar(2, repeat('=', cnt), total)\n    call append(3, s:format_message(valid ? '-' : 'x', name, msg))\n    normal! 2G\n    redraw\n  endfor\n  call setline(1, 'Finished. '.ecnt.' error(s).')\n  normal! gg\n  setlocal nomodifiable\n  if unloaded\n    echo \"Press 'L' on each line to load plugin, or 'U' to update\"\n    nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>\n    xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>\n  end\nendfunction\n\nfunction! s:extract_name(str, prefix, suffix)\n  return matchstr(a:str, '^'.a:prefix.' \\zs[^:]\\+\\ze:.*'.a:suffix.'$')\nendfunction\n\nfunction! s:status_load(lnum)\n  let line = getline(a:lnum)\n  let name = s:extract_name(line, '-', '(not loaded)')\n  if !empty(name)\n    call plug#load(name)\n    setlocal modifiable\n    call setline(a:lnum, substitute(line, ' (not loaded)$', '', ''))\n    setlocal nomodifiable\n  endif\nendfunction\n\nfunction! s:status_update() range\n  let lines = getline(a:firstline, a:lastline)\n  let names = filter(map(lines, 's:extract_name(v:val, \"[x-]\", \"\")'), '!empty(v:val)')\n  if !empty(names)\n    echo\n    execute 'PlugUpdate' join(names)\n  endif\nendfunction\n\nfunction! s:is_preview_window_open()\n  silent! wincmd P\n  if &previewwindow\n    wincmd p\n    return 1\n  endif\nendfunction\n\nfunction! s:find_name(lnum)\n  for lnum in reverse(range(1, a:lnum))\n    let line = getline(lnum)\n    if empty(line)\n      return ''\n    endif\n    let name = s:extract_name(line, '-', '')\n    if !empty(name)\n      return name\n    endif\n  endfor\n  return ''\nendfunction\n\nfunction! s:preview_commit()\n  if b:plug_preview < 0\n    let b:plug_preview = !s:is_preview_window_open()\n  endif\n\n  let sha = matchstr(getline('.'), '^  \\X*\\zs[0-9a-f]\\{7,9}')\n  if empty(sha)\n    let name = matchstr(getline('.'), '^- \\zs[^:]*\\ze:$')\n    if empty(name)\n      return\n    endif\n    let title = 'HEAD@{1}..'\n    let command = 'git diff --no-color HEAD@{1}'\n  else\n    let title = sha\n    let command = 'git show --no-color --pretty=medium '.sha\n    let name = s:find_name(line('.'))\n  endif\n\n  if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir)\n    return\n  endif\n\n  if !s:is_preview_window_open()\n    execute get(g:, 'plug_pwindow', 'vertical rightbelow new')\n    execute 'e' title\n  else\n    execute 'pedit' title\n    wincmd P\n  endif\n  setlocal previewwindow filetype=git buftype=nofile bufhidden=wipe nobuflisted modifiable\n  let batchfile = ''\n  try\n    let [sh, shellcmdflag, shrd] = s:chsh(1)\n    let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && '.command\n    if s:is_win\n      let [batchfile, cmd] = s:batchfile(cmd)\n    endif\n    execute 'silent %!' cmd\n  finally\n    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]\n    if s:is_win && filereadable(batchfile)\n      call delete(batchfile)\n    endif\n  endtry\n  setlocal nomodifiable\n  nnoremap <silent> <buffer> q :q<cr>\n  wincmd p\nendfunction\n\nfunction! s:section(flags)\n  call search('\\(^[x-] \\)\\@<=[^:]\\+:', a:flags)\nendfunction\n\nfunction! s:format_git_log(line)\n  let indent = '  '\n  let tokens = split(a:line, nr2char(1))\n  if len(tokens) != 5\n    return indent.substitute(a:line, '\\s*$', '', '')\n  endif\n  let [graph, sha, refs, subject, date] = tokens\n  let tag = matchstr(refs, 'tag: [^,)]\\+')\n  let tag = empty(tag) ? ' ' : ' ('.tag.') '\n  return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date)\nendfunction\n\nfunction! s:append_ul(lnum, text)\n  call append(a:lnum, ['', a:text, repeat('-', len(a:text))])\nendfunction\n\nfunction! s:diff()\n  call s:prepare()\n  call append(0, ['Collecting changes ...', ''])\n  let cnts = [0, 0]\n  let bar = ''\n  let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)')\n  call s:progress_bar(2, bar, len(total))\n  for origin in [1, 0]\n    let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, \"commit\") || has_key(v:val, \"tag\"))'))))\n    if empty(plugs)\n      continue\n    endif\n    call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')\n    for [k, v] in plugs\n      let branch = s:git_origin_branch(v)\n      if len(branch)\n        let range = origin ? '..origin/'.branch : 'HEAD@{1}..'\n        let cmd = ['git', 'log', '--graph', '--color=never']\n        if s:git_version_requirement(2, 10, 0)\n          call add(cmd, '--no-show-signature')\n        endif\n        call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range])\n        if has_key(v, 'rtp')\n          call extend(cmd, ['--', v.rtp])\n        endif\n        let diff = s:system_chomp(cmd, v.dir)\n        if !empty(diff)\n          let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''\n          call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))\n          let cnts[origin] += 1\n        endif\n      endif\n      let bar .= '='\n      call s:progress_bar(2, bar, len(total))\n      normal! 2G\n      redraw\n    endfor\n    if !cnts[origin]\n      call append(5, ['', 'N/A'])\n    endif\n  endfor\n  call setline(1, printf('%d plugin(s) updated.', cnts[0])\n        \\ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : ''))\n\n  if cnts[0] || cnts[1]\n    nnoremap <silent> <buffer> <plug>(plug-preview) :silent! call <SID>preview_commit()<cr>\n    if empty(maparg(\"\\<cr>\", 'n'))\n      nmap <buffer> <cr> <plug>(plug-preview)\n    endif\n    if empty(maparg('o', 'n'))\n      nmap <buffer> o <plug>(plug-preview)\n    endif\n  endif\n  if cnts[0]\n    nnoremap <silent> <buffer> X :call <SID>revert()<cr>\n    echo \"Press 'X' on each block to revert the update\"\n  endif\n  normal! gg\n  setlocal nomodifiable\nendfunction\n\nfunction! s:revert()\n  if search('^Pending updates', 'bnW')\n    return\n  endif\n\n  let name = s:find_name(line('.'))\n  if empty(name) || !has_key(g:plugs, name) ||\n    \\ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y'\n    return\n  endif\n\n  call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir)\n  setlocal modifiable\n  normal! \"_dap\n  setlocal nomodifiable\n  echo 'Reverted'\nendfunction\n\nfunction! s:snapshot(force, ...) abort\n  call s:prepare()\n  setf vim\n  call append(0, ['\" Generated by vim-plug',\n                \\ '\" '.strftime(\"%c\"),\n                \\ '\" :source this file in vim to restore the snapshot',\n                \\ '\" or execute: vim -S snapshot.vim',\n                \\ '', '', 'PlugUpdate!'])\n  1\n  let anchor = line('$') - 3\n  let names = sort(keys(filter(copy(g:plugs),\n        \\'has_key(v:val, \"uri\") && isdirectory(v:val.dir)')))\n  for name in reverse(names)\n    let sha = has_key(g:plugs[name], 'commit') ? g:plugs[name].commit : s:git_revision(g:plugs[name].dir)\n    if !empty(sha)\n      call append(anchor, printf(\"silent! let g:plugs['%s'].commit = '%s'\", name, sha))\n      redraw\n    endif\n  endfor\n\n  if a:0 > 0\n    let fn = s:plug_expand(a:1)\n    if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?'))\n      return\n    endif\n    call writefile(getline(1, '$'), fn)\n    echo 'Saved as '.a:1\n    silent execute 'e' s:esc(fn)\n    setf vim\n  endif\nendfunction\n\nfunction! s:split_rtp()\n  return split(&rtp, '\\\\\\@<!,')\nendfunction\n\nlet s:first_rtp = s:escrtp(get(s:split_rtp(), 0, ''))\nlet s:last_rtp  = s:escrtp(get(s:split_rtp(), -1, ''))\n\nif exists('g:plugs')\n  let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs))\n  call s:upgrade_specs()\n  call s:define_commands()\nendif\n\nlet &cpo = s:cpo_save\nunlet s:cpo_save\n"
  },
  {
    "path": "test/README.md",
    "content": "Test cases for vim-plug\n=======================\n\n### Prerequisite\n\n- [Vader.vim](https://github.com/junegunn/vader.vim)\n\n### Run\n\n```\n./run\n\n./run !\n```\n\n### TODO\n\nTest cases for the following features are currently missing:\n\n- Output formatting\n- Timeout or interrupt cleaning up git processes\n- User prompt in PlugClean command\n- Single-threaded installer\n- Windows support\n\n"
  },
  {
    "path": "test/functional.vader",
    "content": "Execute (plug#shellescape() works without optional arguments):\n  if has('unix')\n    AssertEqual \"''\", plug#shellescape(\"\")\n    AssertEqual \"'foo'\\\\'''\", plug#shellescape(\"foo'\")\n  endif\n\nExecute (plug#shellescape() ignores invalid optional argument):\n  if has('unix')\n    AssertEqual \"''\", plug#shellescape(\"\", '')\n    AssertEqual \"'foo'\\\\'''\", plug#shellescape(\"foo'\", [])\n  endif\n\nExecute (plug#shellescape() depends on the shell):\n  AssertEqual \"'foo'\\\\'''\", plug#shellescape(\"foo'\", {'shell': 'sh'})\n  AssertEqual '^\"foo''^\"', plug#shellescape(\"foo'\", {'shell': 'cmd.exe'})\n  AssertEqual \"'foo'''\", plug#shellescape(\"foo'\", {'shell': 'powershell'})\n  AssertEqual \"'foo'''\", plug#shellescape(\"foo'\", {'shell': 'powershell.exe'})\n  AssertEqual \"'foo'''\", plug#shellescape(\"foo'\", {'shell': 'pwsh'})\n\nExecute (plug#shellescape() supports non-trivial cmd.exe escaping):\n  \" batchfile\n  AssertEqual '^\"^^%%PATH^^%%^\"', plug#shellescape(\"^%PATH^%\", {\n  \\ 'shell': 'cmd.exe',\n  \\ })\n  AssertEqual '^\"^^%%PATH^^%%^\"', plug#shellescape(\"^%PATH^%\", {\n  \\ 'shell': 'cmd.exe',\n  \\ 'script': 1,\n  \\ })\n  \" command prompt\n  AssertEqual '^\"^^^%PATH^^^%^\"', plug#shellescape(\"^%PATH^%\", {\n  \\ 'shell': 'cmd.exe',\n  \\ 'script': 0,\n  \\ }),\n\nExecute (plug#shellescape() supports non-trivial powershell.exe escaping):\n  AssertEqual '''\\\"Foo\\\\''''\\\\Bar\\\"''', plug#shellescape('\"Foo\\''\\Bar\"', {\n  \\ 'shell': 'powershell',\n  \\ }),\n  AssertEqual '''\\\"Foo\\\\''''\\\\Bar\\\"''', plug#shellescape('\"Foo\\''\\Bar\"', {\n  \\ 'shell': 'powershell.exe',\n  \\ }),\n"
  },
  {
    "path": "test/regressions.vader",
    "content": "**********************************************************************\nExecute (#112 On-demand loading should not suppress messages from ftplugin):\n  call ResetPlug()\n  call plug#begin('$PLUG_FIXTURES')\n  Plug '$PLUG_FIXTURES/ftplugin-msg', { 'for': 'c' }\n  call plug#end()\n\n  redir => out\n  tabnew a.c\n  redir END\n  Assert stridx(out, 'ftplugin-c') >= 0, 'Unexpected output (1): '.out\n\n* The same applies to plug#load())\n  call ResetPlug()\n  redir => out\n  call plug#load('ftplugin-msg')\n  redir END\n  Assert stridx(out, 'ftplugin-c') >= 0, 'Unexpected output (2): '.out\n  q\n\n\n**********************************************************************\nExecute (#114 Should not contain empty path in &rtp):\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  call plug#end()\n\n  Log &rtp\n  Assert &rtp !~ ',,', 'Commas'\n  Assert &rtp !~ '^,', 'Comma prefix'\n  Assert &rtp !~ ',$', 'Comma suffix'\n\n**********************************************************************\nExecute (#130 Proper cleanup of on-demand loading triggers):\n  augroup PlugLOD\n    autocmd!\n  augroup END\n\n  \" Cleared on command\n  call ReloadPlug()\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/vim-emoji', { 'on':  ['EmojiCommand', 'EmojiCommand2', '<Plug>(EmojiMapping)'] }\n  call plug#end()\n  PlugInstall | q\n  call mkdir(g:plugs['vim-emoji'].dir.'/after/plugin', 'p')\n\n  Assert exists(':EmojiCommand'), 'EmojiCommand not defined'\n  Assert exists(':EmojiCommand2'), 'EmojiCommand2 not defined'\n  Assert !empty(mapcheck('<Plug>(EmojiMapping)')), '<Plug>(EmojiMapping) not defined'\n\n  silent! EmojiCommand\n\n  Assert !exists(':EmojiCommand'), 'EmojiCommand defined'\n  Assert !exists(':EmojiCommand2'), 'EmojiCommand2 defined'\n  Assert empty(mapcheck('<Plug>(EmojiMapping)')), '<Plug>(EmojiMapping) defined'\n\n  \" Cleared on FileType\n  call ReloadPlug()\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/vim-emoji', { 'on': ['EmojiCommandExtra', '<Plug>(EmojiMappingExtra)'], 'for': ['emoji'] }\n  call plug#end()\n\n  Assert exists(':EmojiCommandExtra'), 'EmojiCommandExtra not defined'\n  Assert !empty(mapcheck('<Plug>(EmojiMappingExtra)')), '<Plug>(EmojiMappingExtra) not defined'\n\n  setf emoji\n\n  Assert !exists(':EmojiCommandExtra'), 'EmojiCommandExtra defined'\n  Assert empty(mapcheck('<Plug>(EmojiMappingExtra)')), '<Plug>(EmojiMappingExtra) defined'\n\n**********************************************************************\nExecute (#131 Syntax error):\n  call plug#begin('/proc/no-permission')\n  Plug 'junegunn/vim-emoji'\n  call plug#end()\n\n  redir => out\n  silent PlugInstall\n  redir END\n  Assert out =~ 'Invalid plug directory: /proc/no-permission', out\n\n**********************************************************************\nExecute (#139-1 Using new remote branch):\n  \" Make sure to remove the clone\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  call plug#end()\n  PlugClean!\n\n  \" Install master branch\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug expand('file:////tmp/vim-plug-test/new-branch')\n  call plug#end()\n  PlugUpdate\n\n  unlet! g:foo g:bar g:baz\n  call ResetPlug()\n  call plug#load('new-branch')\n  Assert exists('g:foo'),  'g:foo should be found (1)'\n  Assert !exists('g:bar'), 'g:bar should not be found (1)'\n  Assert !exists('g:baz'), 'g:baz should not be found (1)'\n\n  \" Create a new branch on origin\n  call system('cd /tmp/vim-plug-test/new-branch && git checkout -b new &&'\n      \\. 'echo \"let g:bar = 1\" > plugin/bar.vim && git add plugin/bar.vim &&'\n      \\. 'git commit -m second')\n\n  \" We're setting up two plugins so that parallel installer is used\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/seoul256.vim'\n  Plug expand('file:////tmp/vim-plug-test/new-branch'), { 'branch': 'new' }\n  call plug#end()\n  PlugUpdate\n  silent %y\n  Log @\"\n  Assert @\" !~? 'error', 'Should be able to use new remote branch: ' . @\"\n\n  unlet! g:foo g:bar g:baz\n  call ResetPlug()\n  call plug#load('new-branch')\n  Assert exists('g:foo'),  'g:foo should be found (2)'\n  Assert exists('g:bar'),  'g:bar should be found (2)'\n  Assert !exists('g:baz'), 'g:baz should not be found (2)'\n\n  call PlugStatusSorted()\n\nExpect:\n  - new-branch: OK\n  - seoul256.vim: OK\n  Finished. 0 error(s).\n  [==]\n\nExecute (#139-2 Using yet another new remote branch):\n  \" Create another branch on origin\n  call system('cd /tmp/vim-plug-test/new-branch && git checkout master &&'\n      \\. 'git checkout -b brand-new &&'\n      \\. 'echo \"let g:baz = 1\" > plugin/baz.vim && git add plugin/baz.vim &&'\n      \\. 'git commit -m third')\n\n  \" Test Vim installer here\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug expand('file:////tmp/vim-plug-test/new-branch'), { 'branch': 'brand-new' }\n  call plug#end()\n  PlugUpdate\n  silent %y\n  Log @\"\n  Assert @\" !~? 'error', 'Should be able to use new remote branch: ' . @\"\n\n  unlet! g:foo g:bar g:baz\n  call ResetPlug()\n  call plug#load('new-branch')\n  Assert exists('g:foo'),  'g:foo should be found'\n  Assert !exists('g:bar'), 'g:bar should not be found'\n  Assert exists('g:baz'),  'g:baz should be found'\n\n  call PlugStatusSorted()\n\nExpect:\n  - new-branch: OK\n  Finished. 0 error(s).\n  [=]\n\nExecute (#139-3 Should fail when not possible to fast-forward):\n  \" Commit on cloned repo\n  call system('cd /tmp/vim-plug-test/plugged/new-branch && git checkout master &&'\n      \\. 'touch foobar && git add foobar && git commit -m foobar')\n\n  \" Different commit on remote\n  call system('cd /tmp/vim-plug-test/new-branch && git checkout master &&'\n      \\. 'touch foobaz && git add foobaz && git commit -m foobaz')\n\n  for multi in [0, 1]\n    call plug#begin('/tmp/vim-plug-test/plugged')\n    if multi\n      Plug 'junegunn/seoul256.vim'\n    endif\n    Plug expand('file:////tmp/vim-plug-test/new-branch')\n    call plug#end()\n    PlugUpdate\n    silent %y\n    Assert @\" =~ 'Not possible to fast-forward', @\"\n  endfor\n  q\n\n**********************************************************************\nExecute (#145: Merging on-demand loading triggers - cmd):\n  unlet! g:xxx g:yyy\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx', { 'on': 'XXX' }\n  Plug '$PLUG_FIXTURES/yyy', { 'on': ['XXX', 'YYY'] }\n  call plug#end()\n\n  silent! XXX\n\n  Assert exists('g:xxx'), 'xxx is not loaded'\n  Assert exists('g:yyy'), 'yyy is not loaded'\n  Assert !exists(':YYY')\n\nExecute (#145: Merging on-demand loading triggers - map):\n  unlet! g:xxx g:yyy\n\n  call ReloadPlug()\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx', { 'on': '<Plug>(xxx)' }\n  Plug '$PLUG_FIXTURES/yyy', { 'on': ['<Plug>(xxx)' ,'<Plug>(yyy)' ] }\n  call plug#end()\n\n  Assert !empty(mapcheck(\"<Plug>(xxx)\"))\n  Assert !empty(mapcheck(\"<Plug>(yyy)\"))\n\n# FIXME feedkeys() cannot be tested with Vader\n  call plug#load('xxx', 'yyy')\n  Assert empty(mapcheck(\"<Plug>(xxx)\"))\n  Assert empty(mapcheck(\"<Plug>(yyy)\"))\n\n**********************************************************************\nExecute (#159: shell=/bin/tcsh):\n  let org = &shell\n  try\n    set shell=/bin/tcsh\n    call plug#begin('/tmp/vim-plug-test/plugged')\n    Plug 'junegunn/seoul256.vim'\n    call plug#end()\n\n    PlugStatus\n    Log getline(1, '$')\n    q\n    AssertEqual '/bin/tcsh', &shell\n  finally\n    let &shell = org\n  endtry\n\n**********************************************************************\nExecute (#154: Spaces in &rtp should not be escaped):\n  call plug#begin('/tmp/vim-plug-test/plug it')\n  Plug 'foo/seoul256 vim'\n  call plug#end()\n  Log &rtp\n  Assert stridx(&rtp, 'plug it/seoul256 vim') >= 0\n\n**********************************************************************\nExecute (#184: Duplicate entries in &rtp):\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'foo/plugin1'\n    \\| Plug 'foo/plugin0'\n\n  Plug 'foo/plugin2'\n    \\| Plug 'foo/plugin0'\n    \\| Plug 'foo/plugin1'\n  call plug#end()\n\n  Log &rtp\n  AssertEqual 3, len(filter(split(&rtp, ','), 'stridx(v:val, \"plugged\") >= 0'))\n\n**********************************************************************\nExecute (#236: Plugin removed from &rtp when .vimrc is reloaded):\n  unlet! g:loaded_easy_align_plugin\n  silent! delc EasyAlign\n\n  call ReloadPlug()\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/vim-easy-align', { 'on': 'EasyAlign' }\n  call plug#end()\n  PlugInstall | q\n\n  Assert &rtp !~ '/vim-easy-align', 'Plugin should not be in &rtp'\n  %EasyAlign=\n  Assert &rtp =~ '/vim-easy-align', 'Plugin should be in &rtp'\n\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/vim-easy-align', { 'on': 'EasyAlign' }\n  call plug#end()\n  Assert &rtp =~ '/vim-easy-align', 'Plugin should still be in &rtp'\n\n**********************************************************************\nExecute (#350: Ruby installer failed to unshallow tagged plugin on update):\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  call plug#end()\n  PlugClean!\n\n  \" Shallow clone. We should have at least 2 plugins to enable parallel installer.\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/vim-easy-align'\n  Plug 'junegunn/seoul256.vim'\n  call plug#end()\n  PlugUpdate\n  Assert filereadable(g:plugs['vim-easy-align'].dir.'/.git/shallow')\n\n  \" Now unshallowed\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/vim-easy-align', { 'tag': '2.9.0' }\n  Plug 'junegunn/seoul256.vim'\n  call plug#end()\n  PlugUpdate\n  Assert !filereadable(g:plugs['vim-easy-align'].dir.'/.git/shallow')\n  q\n\n**********************************************************************\nExecute (#474: Load ftdetect files in filetypedetect augroup):\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/rust.vim', { 'for': 'rust', 'commit': '115d321d383eb96d438466c56cc871fcc1bd0faa' }\n  call plug#end()\n  PlugInstall!\n  q\n\n  tabnew /tmp/vim-plug-test/any.rs\n  AssertEqual 'rust', &filetype\n  Log &filetype\n  filetype detect\n  AssertEqual 'rust', &filetype\n  Log &filetype\n  bd\n\n**********************************************************************\nExecute (#489/#587 On-demand loading with 'on' option should trigger BufRead autocmd w/o nomodeline):\n  call plug#begin('$PLUG_FIXTURES')\n  Plug 'foo/ftplugin-msg', { 'on': 'XXX' }\n  call plug#end()\n\n  tabnew a.java\n  call setline(1, '// vim: set filetype=lava:')\n  redir => out\n  silent! XXX\n  redir END\n  Assert stridx(out, 'ftplugin-java') >= 0\n  AssertEqual 'lava', &filetype\n  q!\n\n**********************************************************************\nExecute (Cursor moved to another window during post-update hook):\n  function! DoSplit(...)\n    new\n    call setline(1, 'empty')\n  endfunction\n  call plug#begin('/tmp/vim-plug-test/plugged')\n  Plug 'junegunn/rust.vim', { 'do': function('DoSplit') }\n  call plug#end()\n  PlugInstall!\n  AssertEqual 1, line('$')\n  AssertEqual 'empty', getline(1)\n  q!\n  q\n\n**********************************************************************\nExecute (#593 Add plugin to &rtp before running post-update hook with : prefix):\n  call ReloadPlug()\n  call plug#begin()\n  Plug 'junegunn/vim-pseudocl', { 'on': 'XXX', 'do': ':let g:bar = pseudocl#complete#extract_words(''a b'')' }\n  call plug#end()\n  PlugInstall!\n  AssertEqual ['a', 'b'], g:bar\n\n**********************************************************************\nExecute (#602 Confusion with branch name and path name):\n  call plug#begin()\n  Plug expand('file:////tmp/vim-plug-test/new-branch'), { 'branch': 'plugin' }\n  call plug#end()\n  PlugUpdate\n  call PlugStatusSorted()\n\nExpect:\n  - new-branch: OK\n  Finished. 0 error(s).\n  [=]\n\n**********************************************************************\nExecute (PlugStatus showed error with wildcard tag):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'tag': '*' }\n  call plug#end()\n  PlugUpdate\n  call PlugStatusSorted()\n\nExpect:\n  - vim-easy-align: OK\n  Finished. 0 error(s).\n  [=]\n"
  },
  {
    "path": "test/run",
    "content": "#!/bin/bash\n\n# Privileged mode, ignores $CDPATH etc.\nset -p\nset -eu\n\ncd \"$(dirname \"${BASH_SOURCE[0]}\")\"\n\nexport BASE=\"$PWD\"\nexport PLUG_SRC=\"$PWD/../plug.vim\"\nexport PLUG_FIXTURES=\"$PWD/fixtures\"\nmkdir -p \"$PLUG_FIXTURES\"\nexport TEMP=/tmp/vim-plug-test\nrm -rf \"$TEMP\"\nmkdir -p \"$TEMP\"\n\ncat > $TEMP/mini-vimrc << VIMRC\nset rtp+=$TEMP/junegunn/vader.vim\nset shell=/bin/bash\nVIMRC\n\nclone() {\n  if [ ! -d \"$2\" ]; then\n    git clone \"$1\" \"$2\"\n  fi\n}\n\nclone_repos() (\n  cd $TEMP\n  mkdir -p junegunn vim-scripts jg\n  for repo in vader.vim goyo.vim rust.vim seoul256.vim vim-easy-align vim-fnr \\\n              vim-oblique vim-pseudocl vim-redis vim-emoji; do\n    clone https://github.com/junegunn/${repo}.git junegunn/$repo &\n  done\n  clone https://github.com/vim-scripts/beauty256.git vim-scripts/beauty256 &\n  clone https://github.com/junegunn/fzf.git fzf &\n  clone https://github.com/yous/subsubmodule.git yous/subsubmodule && \\\n    (cd yous/subsubmodule && git submodule update --init --recursive &) &\n  wait\n\n  clone junegunn/vim-emoji jg/vim-emoji\n  cd junegunn/seoul256.vim && git checkout no-t_co && git checkout master\n)\n\nmake_dirs() (\n  rm -rf \"$PLUG_FIXTURES/$1\"\n  mkdir -p \"$PLUG_FIXTURES/$1\"\n  cd \"$PLUG_FIXTURES/$1\"\n  mkdir -p autoload colors ftdetect ftplugin indent plugin syntax\n  for d in *; do\n    [ -d \"$d\" ] || continue\n    cat > \"$d/xxx.vim\" << EOF\n    \" echom expand('<sfile>')\n    let g:total_order = get(g:, 'total_order', [])\n    let g:$2 = get(g:, '$2', [])\n    let s:name = join(filter(['$2', '${1:4}', '$d'], '!empty(v:val)'), '/')\n    call add(g:$2, s:name)\n    call add(g:total_order, s:name)\nEOF\n  done\n)\n\ngitinit() (\n  cd \"$PLUG_FIXTURES/$1\"\n  git init -b master\n  git commit -m 'commit' --allow-empty\n)\n\nprepare() {\n  make_dirs xxx/ xxx\n  make_dirs xxx/after xxx\n  mkdir -p \"$PLUG_FIXTURES/xxx/doc\"\n  cat > \"$PLUG_FIXTURES/xxx/doc/xxx.txt\" << DOC\nhello *xxx*\nDOC\n  gitinit xxx\n\n  make_dirs yyy/ yyy\n  make_dirs yyy/after yyy\n  mkdir -p \"$PLUG_FIXTURES/yyy/rtp/doc\"\n  cat > \"$PLUG_FIXTURES/yyy/rtp/doc/yyy.txt\" << DOC\nhello *yyy*\nDOC\n  gitinit yyy\n\n  make_dirs z1/ z1\n  make_dirs z2/ z2\n\n  rm -rf \"$PLUG_FIXTURES/ftplugin-msg\"\n  mkdir -p \"$PLUG_FIXTURES\"/ftplugin-msg/{plugin,ftplugin}\n  echo \"echomsg 'ftplugin-c'\" > \"$PLUG_FIXTURES/ftplugin-msg/ftplugin/c.vim\"\n  echo \"echomsg 'ftplugin-java'\" > \"$PLUG_FIXTURES/ftplugin-msg/ftplugin/java.vim\"\n\n  chmod +w \"$PLUG_FIXTURES/cant-delete/autoload\" || rm -rf \"$PLUG_FIXTURES/cant-delete\"\n  mkdir -p \"$PLUG_FIXTURES/cant-delete/autoload\"\n  touch \"$PLUG_FIXTURES/cant-delete/autoload/cant-delete.vim\"\n  chmod -w \"$PLUG_FIXTURES/cant-delete/autoload\"\n\n  rm -rf $TEMP/new-branch\n  cd $TEMP\n  git init new-branch -b master\n  cd new-branch\n  mkdir plugin\n  echo 'let g:foo = 1' > plugin/foo.vim\n  git add plugin/foo.vim\n  git commit -m initial\n  git checkout -b plugin\n  git checkout master\n\n  cd \"$BASE\"\n}\n\nselect_vim() {\n  local vim=/usr/bin/vim\n  if [ -n \"${DEPS:-}\" ] && [ -e \"${DEPS}/bin/vim\" ]; then\n    vim=\"${DEPS}/bin/vim\"\n  elif [ -e \"/usr/local/bin/vim\" ]; then\n    vim=/usr/local/bin/vim\n  fi\n  echo $vim\n}\n\nclone_repos\nprepare\n\ngit --version\nvim=$(select_vim)\necho \"Selected Vim: $vim\"\nif [ \"${1:-}\" = '!' ]; then\n  FAIL=0\n  $vim -Nu $TEMP/mini-vimrc -c 'Vader! test.vader' > /dev/null || FAIL=1\n  prepare\n  $vim -Nu $TEMP/mini-vimrc -c 'let g:plug_threads = 1 | Vader! test.vader' > /dev/null || FAIL=1\n  test $FAIL -eq 0\nelse\n  $vim -Nu $TEMP/mini-vimrc -c 'Vader test.vader'\nfi\n"
  },
  {
    "path": "test/test.vader",
    "content": "Execute (Initialize test environment):\n  Save &rtp, g:plugs, g:plug_home, g:plug_window\n  unlet! g:plugs g:plug_home g:plug_window\n\n  let g:plug_url_format = 'file:///tmp/vim-plug-test/%s'\n  let g:base_rtp        = &rtp\n  let g:first_rtp       = split(&rtp, ',')[0]\n  let g:last_rtp        = split(&rtp, ',')[-1]\n  let g:temp_plugged    = tempname()\n  if !exists('$PLUG_SRC')\n    let $PLUG_SRC = globpath(&rtp, 'autoload/plug.vim')\n  endif\n  let $PLUG_TMP = fnamemodify(tempname(), ':h').'/plug.vim'\n\n  \" Temporarily patch plug.vim\n  call system('cp \"$PLUG_SRC\" \"$PLUG_TMP\"')\n  let patch =\n  \\ ['function! ResetPlug()', 'let s:loaded = {}', 'endfunction',\n  \\  'function! CompareURI(a, b)', 'return s:compare_git_uri(a:a, a:b)', 'endfunction']\n\n  call writefile(extend(readfile($PLUG_TMP), patch), $PLUG_TMP)\n\n  set t_Co=256\n  colo default\n  pclose\n\n  function! PlugStatusSorted()\n    PlugStatus\n    %y\n    q\n    normal! P\n    %sort\n    g/^$/d\n  endfunction\n\n  function! AssertExpect(bang, pat, cnt, ...)\n    let op = a:bang ? '==#' : '=~#'\n    let args = [a:cnt, len(filter(getline(1, '$'), \"v:val \".op.\" '\".a:pat.\"'\"))] + a:000\n    call call('vader#assert#equal', args)\n  endfunction\n  command! -nargs=+ -bang AssertExpect call AssertExpect('<bang>' == '!', <args>)\n\n  function! EnsureLoaded()\n    if has('vim_starting')\n      runtime! plugin/**/*.vim\n    endif\n  endfunction\n\n  function! RmRf(file)\n    call system(printf('rm -rf \"%s\"', a:file))\n  endfunction\n\n  function! ReloadPlug()\n    call ResetPlug()\n    source $PLUG_TMP\n    let &rtp = g:base_rtp\n  endfunction\n\n  function! GitBranch(repo)\n    return system(printf('cd %s && git rev-parse --abbrev-ref HEAD', g:plugs[a:repo].dir))[:-2]\n  endfunction\n\n  function! GitTag(repo)\n    return system(printf('cd %s && git describe --tags', g:plugs[a:repo].dir))[:-2]\n  endfunction\n\n  function! GitCommit(repo)\n    return system(printf('cd %s && git rev-parse HEAD', g:plugs[a:repo].dir))[:-2]\n  endfunction\n\n  source $PLUG_TMP\n\nExecute (Print Interpreter Version):\n  redir => out\n  if has('ruby')\n    silent! ruby puts 'Ruby: ' + RUBY_VERSION\n  endif\n  if has('python')\n    silent! python import sys; svi = sys.version_info; print 'Python: {}.{}.{}'.format(svi[0], svi[1], svi[2])\n  endif\n  if has('python3')\n    silent! python3 import sys; svi = sys.version_info; print('Python: {}.{}.{}'.format(svi[0], svi[1], svi[2]))\n  endif\n  redir END\n  Log split(out, '\\n')\n\nInclude: workflow.vader\nInclude: regressions.vader\nInclude: functional.vader\n\nExecute (Cleanup):\n  silent! call RmRf(g:temp_plugged)\n  silent! unlet g:plugs g:plug_home g:plug_url_format\n  silent! unlet g:temp_plugged g:first_rtp g:last_rtp g:base_rtp out\n  silent! delf PlugStatusSorted\n  silent! delf AssertExpect\n  silent! delf PlugUpdated\n  silent! delf EnsureLoaded\n  silent! delf ReloadPlug\n  silent! delc AssertExpect\n  silent! unmap /\n  silent! unmap ?\n  call delete($PLUG_TMP)\n\n  Restore\n\n"
  },
  {
    "path": "test/workflow.vader",
    "content": "Execute (plug#end() before plug#begin() should fail):\n  redir => out\n  silent! AssertEqual 0, plug#end()\n  redir END\n  Assert stridx(out, 'plug#end() called without calling plug#begin() first') >= 0\n\nExecute (plug#begin() without path argument):\n  call plug#begin()\n  AssertEqual split(&rtp, ',')[0].'/plugged', g:plug_home\n  unlet g:plug_home\n\nExecute (plug#begin() without path argument with empty &rtp):\n  let save_rtp = &rtp\n  set rtp=\n  redir => out\n  AssertEqual 0, plug#begin()\n  redir END\n  Assert stridx(out, 'Unable to determine plug home') >= 0\n  let &rtp = save_rtp\n  unlet save_rtp\n\nExecute (Standard runtime path is not allowed):\n  redir => out\n  silent! AssertEqual 0, plug#begin(split(&rtp, ',')[0].'/plugin')\n  redir END\n  Log out\n  Assert stridx(out, 'Invalid plug home') >= 0\n\nExecute (plug#begin(path)):\n  call plug#begin(g:temp_plugged.'/')\n  Assert g:plug_home !~ '[/\\\\]$', 'Trailing / should be stripped from g:plug_home'\n\n  AssertEqual 0, len(g:plugs)\n  AssertEqual g:temp_plugged, g:plug_home\n  AssertEqual g:base_rtp, &rtp\n\nExecute (Subsequent plug#begin() calls will reuse g:plug_home):\n  call plug#begin()\n  AssertEqual g:temp_plugged, g:plug_home\n\nExecute (Test Plug command):\n^ Git repo with branch (DEPRECATED. USE BRANCH OPTION)\n  Plug 'junegunn/seoul256.vim', { 'branch': 'yes-t_co' }\n  AssertEqual 'file:///tmp/vim-plug-test/junegunn/seoul256.vim', g:plugs['seoul256.vim'].uri\n  AssertEqual join([g:temp_plugged, 'seoul256.vim/'], '/'), g:plugs['seoul256.vim'].dir\n  AssertEqual 'yes-t_co', g:plugs['seoul256.vim'].branch\n\n  Plug 'junegunn/seoul256.vim', { 'branch': 'no-t_co' } \" Using branch option\n  AssertEqual 'no-t_co', g:plugs['seoul256.vim'].branch\n\n^ Git repo with tag (DEPRECATED. USE TAG OPTION)\n  redir => out\n  silent Plug 'foo/bar.vim', ''\n  redir END\n  Assert out =~ 'Invalid argument for \"tag\" option of :Plug (expected: string)'\n  Plug 'junegunn/goyo.vim', '1.5.2'\n  AssertEqual 'file:///tmp/vim-plug-test/junegunn/goyo.vim', g:plugs['goyo.vim'].uri\n  AssertEqual join([g:temp_plugged, 'goyo.vim/'], '/'), g:plugs['goyo.vim'].dir\n  AssertEqual '1.5.2', g:plugs['goyo.vim'].tag\n\n  redir => out\n  silent Plug 'foo/bar.vim', {'tag': ''}\n  redir END\n  Assert out =~ 'Invalid argument for \"tag\" option of :Plug (expected: string)'\n  Plug 'junegunn/goyo.vim', { 'tag': '1.5.3' } \" Using tag option\n  AssertEqual '1.5.3', g:plugs['goyo.vim'].tag\n\n  \" Git URI\n  Plug 'file:///tmp/vim-plug-test/jg/vim-emoji'\n  AssertEqual 'file:///tmp/vim-plug-test/jg/vim-emoji', g:plugs['vim-emoji'].uri\n  AssertEqual '', g:plugs['vim-emoji'].branch\n  AssertEqual join([g:temp_plugged, 'vim-emoji/'], '/'), g:plugs['vim-emoji'].dir\n\n  \" vim-scripts/\n  Plug 'vim-scripts/beauty256'\n  AssertEqual 'file:///tmp/vim-plug-test/vim-scripts/beauty256', g:plugs.beauty256.uri\n  AssertEqual '', g:plugs.beauty256.branch\n\n  AssertEqual 4, len(g:plugs)\n\n  redir => out\n  Plug 'beauty256'\n  redir END\n  Assert out =~ 'Invalid argument: beauty256'\n\nExecute (Plug command with dictionary option):\n  Log string(g:plugs)\n  for opt in ['branch', 'tag', 'commit', 'rtp', 'dir', 'as']\n    let opts = {}\n    let opts[opt] = ''\n    redir => out\n    silent Plug 'foo/bar.vim', opts\n    redir END\n    Assert out =~ 'Invalid argument for \"'.opt.'\" option of :Plug (expected: string)'\n  endfor\n  for opt in ['on', 'for']\n    let opts = {}\n    let opts[opt] = ''\n    redir => out\n    silent Plug 'foo/bar.vim', opts\n    redir END\n    Assert out =~ 'Invalid argument for \"'.opt.'\" option of :Plug (expected: string or list)'\n  endfor\n  redir => out\n  silent Plug 'foo/bar.vim', {'do': ''}\n  redir END\n  Assert out =~ 'Invalid argument for \"do\" option of :Plug (expected: string or funcref)'\n  Plug 'junegunn/seoul256.vim', { 'branch': 'no-t_co', 'rtp': '././' }\n  AssertEqual join([g:temp_plugged, 'seoul256.vim/'], '/'), g:plugs['seoul256.vim'].dir\n  AssertEqual '././', g:plugs['seoul256.vim'].rtp\n\n  Log string(g:plugs)\n  AssertEqual 4, len(g:plugs)\n\nExecute (PlugStatus before installation):\n  PlugStatus\n  AssertExpect 'Not found', 4\n  q\n\nExecute (PlugClean before installation):\n  PlugClean\n  AssertExpect 'Already clean', 1\n  q\n\nExecute (plug#end() updates &rtp):\n  \" Plug 'junegunn/goyo.vim', { 'tag': '1.5.3' }\n  \" Plug 'file:///tmp/vim-plug-test/jg/vim-emoji'\n  \" Plug 'beauty256'\n  \" Plug 'junegunn/seoul256.vim', { 'branch': 'no-t_co', 'rtp': '././' }\n  call plug#end()\n  Assert len(&rtp) > len(g:base_rtp)\n  AssertEqual g:first_rtp, split(&rtp, ',')[0]\n  AssertEqual g:last_rtp, split(&rtp, ',')[-1]\n\nExecute (Yet, plugins are not available):\n  Assert empty(globpath(&rtp, 'autoload/emoji.vim'))\n\nExecute (PlugInstall):\n  PlugInstall\n  q\n\nExecute (Plugin available after installation):\n  Assert !empty(globpath(&rtp, 'autoload/emoji.vim'))\n\nExecute (PlugClean after installation):\n  PlugClean\n  AssertExpect 'Already clean', 1\n  q\n\nExecute (PlugStatus after installation):\n  PlugStatus\n  Log getline(1, '$')\n  AssertExpect 'OK', 4\n  q\n\nExecute (PlugUpdate - tagged plugin should not fail (#174)):\n  PlugUpdate goyo.vim\n  Log getline(1, '$')\n  AssertExpect '^- goyo.vim', 1\n  q\n\nExecute (Change tag of goyo.vim):\n  call plug#begin()\n  Plug 'junegunn/goyo.vim', { 'tag': '9.9.9' }\n  call plug#end()\n\nExecute (PlugStatus):\n  call PlugStatusSorted()\n\nExpect:\n      Invalid tag: 1.5.3 (expected: 9.9.9). Try PlugUpdate.\n  Finished. 1 error(s).\n  [=]\n  x goyo.vim:\n\nExecute (Remove tag of goyo.vim):\n  call plug#begin()\n  Plug 'junegunn/goyo.vim'\n  call plug#end()\n\nExecute (PlugStatus):\n  call PlugStatusSorted()\n\nExpect:\n      Invalid branch: HEAD (expected: master). Try PlugUpdate.\n  Finished. 1 error(s).\n  [=]\n  x goyo.vim:\n\nExecute (PlugUpdate to set the right branch):\n  PlugUpdate\n  call PlugStatusSorted()\n\nExpect:\n  - goyo.vim: OK\n  Finished. 0 error(s).\n  [=]\n\nExecute (Change branch of seoul256.vim):\n  call plug#begin()\n  Plug 'junegunn/seoul256.vim'\n  Plug 'file:///tmp/vim-plug-test/jg/vim-emoji'\n  call plug#end()\n\nExecute (PlugStatus):\n  call PlugStatusSorted()\n\nExpect:\n      Invalid branch: no-t_co (expected: master). Try PlugUpdate.\n  - vim-emoji: OK\n  Finished. 1 error(s).\n  [==]\n  x seoul256.vim:\n\nExecute (PlugUpdate to switch branch, then PlugStatus):\n  PlugUpdate\n  call PlugStatusSorted()\n\nExpect:\n  - seoul256.vim: OK\n  - vim-emoji: OK\n  Finished. 0 error(s).\n  [==]\n\nExecute (Change tag of seoul256.vim):\n  call plug#begin()\n  Plug 'junegunn/seoul256.vim', { 'tag': 'no-such-tag' }\n  call plug#end()\n  call PlugStatusSorted()\n\nExpect:\n      Invalid tag: N/A (expected: no-such-tag). Try PlugUpdate.\n  Finished. 1 error(s).\n  [=]\n  x seoul256.vim:\n\nExecute (Change URI of seoul256.vim):\n  call plug#begin()\n  Plug 'junegunn.choi/seoul256.vim'\n  Plug 'file:///tmp/vim-plug-test/jg/vim-emoji'\n  call plug#end()\n\nExecute (PlugStatus):\n  call PlugStatusSorted()\n\nExpect:\n      Expected:    file:///tmp/vim-plug-test/junegunn.choi/seoul256.vim\n      Invalid URI: file:///tmp/vim-plug-test/junegunn/seoul256.vim\n      PlugClean required.\n  - vim-emoji: OK\n  Finished. 1 error(s).\n  [==]\n  x seoul256.vim:\n\nExecute (Corrected the URI but ahead of upstream):\n  call plug#begin()\n  Plug 'junegunn/seoul256.vim'\n  Plug 'file:///tmp/vim-plug-test/jg/vim-emoji'\n  call plug#end()\n  for _ in range(3)\n    call system(printf('cd \"%s\" && git commit --allow-empty -m \"dummy\"', g:plugs['seoul256.vim'].dir))\n  endfor\n  call PlugStatusSorted()\n\nExpect:\n      Ahead of origin/master by 3 commit(s).\n      Cannot update until local changes are pushed.\n  - vim-emoji: OK\n  Finished. 1 error(s).\n  [==]\n  x seoul256.vim:\n\n# TODO: does not work due to inputsave()\n# Do (PlugClean):\n#   :PlugClean\\<Enter>y\\<Enter>\n#   ggyG\n#   q\n#   PGdd\n\nExecute (PlugClean! keeps seoul256.vim):\n  PlugClean!\n  \" Two removed, emoji and seoul256 left\n  AssertEqual 'Removed 2 directories.', getline(4)\n  AssertExpect '^\\~ ', 2\n  AssertExpect 'Diverged', 0\n  Assert !empty(globpath(&rtp, 'colors/seoul256.vim'))\n  Assert !empty(globpath(&rtp, 'autoload/emoji.vim'))\n  q\n\nExecute (Make seoul256 to be diverged):\n  call plug#begin()\n  Plug 'junegunn/seoul256.vim'\n  Plug 'file:///tmp/vim-plug-test/jg/vim-emoji'\n  call plug#end()\n  call system(printf(join([\n    \\ 'cd \"%s\"',\n    \\ 'git fetch --unshallow',\n    \\ 'git reset \"@{u}~1\"',\n    \\ 'git commit --allow-empty -m \"diverged1\"',\n    \\ 'git commit --allow-empty -m \"diverged2\"'], ' && '),\n    \\ g:plugs['seoul256.vim'].dir))\n  Assert empty(v:shell_error), 'Got shell error: '.v:shell_error\n  call PlugStatusSorted()\n\nExpect:\n      Backup local changes and run PlugClean and PlugUpdate to reinstall it.\n      Diverged from origin/master (2 commit(s) ahead and 1 commit(s) behind!\n  - vim-emoji: OK\n  Finished. 1 error(s).\n  [==]\n  x seoul256.vim:\n\nExecute (PlugClean! removes seoul256.vim):\n  PlugClean!\n  \" One removed, emoji left\n  AssertEqual 'Removed 1 directories.', getline(4)\n  AssertExpect '^\\~ ', 1\n  AssertExpect 'Diverged', 1\n  Assert empty(globpath(&rtp, 'colors/seoul256.vim'))\n  Assert !empty(globpath(&rtp, 'autoload/emoji.vim'))\n  q\n\nExecute (Change GIT URI of vim-emoji):\n  call plug#begin()\n  Plug 'junegunn/seoul256.vim'\n  Plug 'junegunn/vim-emoji'\n  call plug#end()\n\nExecute (PlugStatus):\n  call PlugStatusSorted()\n\nExpect:\n      Expected:    file:///tmp/vim-plug-test/junegunn/vim-emoji\n      Invalid URI: file:///tmp/vim-plug-test/jg/vim-emoji\n      Not found. Try PlugInstall.\n      PlugClean required.\n  Finished. 2 error(s).\n  [==]\n  x seoul256.vim:\n  x vim-emoji:\n\nExecute (PlugClean! to remove vim-emoji):\n  PlugClean!\n  AssertExpect '^\\~ ', 1\n  AssertEqual 'Removed 1 directories.', getline(4)\n  Assert empty(globpath(&rtp, 'colors/seoul256.vim')), 'seoul256.vim was removed'\n  Assert empty(globpath(&rtp, 'autoload/emoji.vim')), 'emoji was removed'\n  q\n\nExecute (PlugUpdate to install both again):\n  PlugUpdate\n  AssertExpect '^- [^:]*:', 2\n  Assert !empty(globpath(&rtp, 'colors/seoul256.vim')), 'seoul256.vim should be found'\n  Assert !empty(globpath(&rtp, 'autoload/emoji.vim')), 'vim-emoji should be found'\n  q\n\nExecute (PlugUpdate only to find out plugins are up-to-date, D key to check):\n  PlugUpdate\n  AssertExpect 'Already up.to.date', 2, 'Expected 2 times \"Already up-to-date\", but got: '.string(getline(1, '$'))\n  normal D\n  AssertEqual '0 plugin(s) updated.', getline(1)\n  q\n\nExecute (PlugDiff - 'No updates.'):\n  PlugDiff\n  Log getline(1, '$')\n  AssertEqual '0 plugin(s) updated.', getline(1)\n  Assert empty(mapcheck('o'))\n  Assert empty(mapcheck('X'))\n  Assert empty(mapcheck(\"\\<cr>\"))\n  q\n\nExecute (New commits on remote, PlugUpdate, then PlugDiff):\n  let g:plug_window = 'vertical topleft new'\n  let g:plug_pwindow = 'above 12new'\n\n  for repo in ['seoul256.vim', 'vim-emoji']\n    for _ in range(2)\n      call system(printf('cd /tmp/vim-plug-test/junegunn/%s && git commit --allow-empty -m \"update\"', repo))\n    endfor\n  endfor\n  unlet repo\n  PlugUpdate\n\n  \" Now we have updates\n  normal D\n  AssertEqual '2 plugin(s) updated.', getline(1)\n  AssertThrows execute('/gpg')\n\n  \" Preview commit\n  silent! wincmd P\n  AssertEqual 0, &previewwindow\n\n  \" ]] motion\n  execute 'normal ]]'\n  let lnum = line('.')\n  AssertEqual 3, col('.')\n\n  \" Open full diff (empty)\n  execute \"normal \\<cr>\"\n  wincmd P\n  AssertEqual 1, &previewwindow\n  AssertEqual 'git', &filetype\n  AssertEqual [''], getline(1, '$')\n  pclose\n\n  \" Open commit preview\n  execute \"normal j\\<cr>\"\n  wincmd P\n  AssertEqual 1, &previewwindow\n  AssertEqual 'git', &filetype\n\n  \" Close preview window\n  pclose\n\n  \" Open and go to preview window with a custom mapping\n  nmap <buffer> <c-o> <plug>(plug-preview)<c-w>P\n  execute \"normal \\<c-o>\"\n  AssertEqual 1, &previewwindow, 'Should be on preview window'\n  normal q\n  AssertEqual 0, &previewwindow, 'Should not be on preview window'\n\n  \" ]] motion\n  execute 'normal $]]'\n  Assert line('.') >= 4\n    \" 5+ for merge commit\n  AssertEqual 3, col('.')\n\n  \" [[ motion\n  execute 'normal 0[['\n  AssertEqual lnum, line('.')\n  unlet lnum\n  AssertEqual 3, col('.')\n\n  \" X key to revert the update\n  AssertExpect '^- ', 2\n  execute \"normal Xn\\<cr>\"\n  AssertExpect '^- ', 2\n  execute \"normal Xy\\<cr>\"\n  AssertExpect '^- ', 1\n\n  \" q will only close preview window\n  normal q\n\n  \" We no longer have preview window\n  silent! wincmd P\n  AssertEqual 0, &previewwindow\n\n  \" And we're still on main vim-plug window\n  AssertEqual 'vim-plug', &filetype\n  normal q\n\n  \" q should not close preview window if it's already open\n  pedit\n  PlugDiff\n  AssertExpect '^- ', 1\n  execute \"normal ]]j\\<cr>\"\n  normal q\n\n  silent! wincmd P\n  AssertEqual 1, &previewwindow\n  pclose\n\n  unlet g:plug_window g:plug_pwindow\n\nExecute (Test g:plug_pwindow):\n  let g:plug_pwindow = 'below 5new'\n  PlugDiff\n  AssertExpect '^- ', 1\n  execute \"normal ]]jo\"\n\n  AssertEqual 0, &previewwindow\n  AssertEqual 1, winnr()\n  wincmd P\n  AssertEqual 1, &previewwindow\n  AssertEqual 2, winnr()\n  AssertEqual 5, winheight('.')\n  wincmd p\n\n  \" Close preview window\n  normal q\n\n  \" Close main window\n  normal q\n  unlet g:plug_pwindow\n\nExecute (#572 - Commit preview should work with non-POSIX-compliant &shell):\n  \" Invalid shell\n  let shell = &shell\n  set shell=shellfish\n\n  try\n    \" Preview commit should still work\n    PlugDiff\n    execute \"normal ]]jo\"\n    wincmd P\n    Log getline(1, '$')\n    Assert getline(1) =~ 'commit', 'Preview window is empty'\n    AssertEqual 'shellfish', &shell\n  finally\n    \" Restore &shell\n    let &shell = shell\n    unlet shell\n    pclose\n    q\n  endtry\n\nExecute (Reuse Plug window in another tab):\n  let tabnr = tabpagenr()\n  PlugDiff\n  tab new new-tab\n  set buftype=nofile\n  PlugUpdate\n  normal D\n  AssertExpect '^- ', 1\n  normal q\n  AssertEqual tabnr, tabpagenr()\n  normal! gt\n  q\n  unlet tabnr\n\nExecute (contd. PlugDiff should not show inverted history):\n  \" Additional PlugUpdate to clear diff\n  PlugUpdate\n  PlugDiff\n  Log getline(1, '$')\n\n  \" Checking out older revisions\n  for repo in values(g:plugs)\n    call system(printf('cd %s && git reset HEAD^ --hard', shellescape(repo.dir)))\n  endfor\n  unlet repo\n\n  \" PlugDiff should not report the changes i.e. git log --left-only\n  PlugDiff\n  Log getline(1, '$')\n  AssertEqual '0 plugin(s) updated.', getline(1)\n  q\n\n**********************************************************************\n~ PlugDiff to see the pending changes\n**********************************************************************\n\nExecute (PlugDiff):\n  call plug#begin()\n  call plug#end()\n  PlugClean!\n\n  call plug#begin()\n  Plug 'file://'.expand('$PLUG_FIXTURES').'/xxx'\n  Plug 'file://'.expand('$PLUG_FIXTURES').'/yyy'\n  call plug#end()\n  PlugInstall\n  Log getline(1, '$')\n\n  call system('cd \"$PLUG_FIXTURES/xxx\" && git commit --allow-empty -m update-xxx && git tag -f xxx')\n  call system('cd \"$PLUG_FIXTURES/yyy\" && git tag -f yyy && git commit --allow-empty -m update-yyy && git tag -f zzz')\n\n  let g:plugs.yyy.tag = 'yyy'\n  PlugUpdate\n  Log getline(1, '$')\n\n  PlugDiff\n  \" 1 plugin(s) updated. 1 plugin(s) have pending updates.\n  \" [==]\n  \"\n  \" Last update:\n  \" ------------\n  \"\n  \" - xxx:\n  \"   166cfff (tag: xxx) update-xxx (1 second ago)\n  \"\n  \" Pending updates:\n  \" ----------------\n  \"\n  \" - yyy: (tag: yyy)\n  \"   c0a064b (tag: zzz) update-yyy (1 second ago)\n  \"\n  Log getline(1, '$')\n  AssertEqual 15, line('$')\n  AssertEqual '1 plugin(s) updated. 1 plugin(s) have pending updates.', getline(1)\n  AssertEqual '[==]', getline(2)\n  AssertEqual '- yyy: (tag: yyy)', getline(13)\n  Assert getline(8) =~ '(tag: xxx)'\n  Assert getline(14) =~ '(tag: zzz)'\n  Assert !empty(mapcheck('o'))\n  Assert !empty(mapcheck('X'))\n  Assert !empty(mapcheck(\"\\<cr>\"))\n  q\n\nExecute (Do not show diff for commits outside of rtp):\n  call plug#begin()\n  call plug#end()\n  PlugClean!\n\n  call plug#begin()\n  Plug 'file://'.expand('$PLUG_FIXTURES').'/xxx'\n  Plug 'file://'.expand('$PLUG_FIXTURES').'/yyy', { 'rtp': 'rtp' }\n  call plug#end()\n  PlugInstall\n  Log getline(1, '$')\n\n  call system('cd \"$PLUG_FIXTURES/xxx\" && git commit --allow-empty -m update-xxx && git tag -f xxx')\n  call system('cd \"$PLUG_FIXTURES/yyy\" && git commit --allow-empty -m update-yyy && git tag -f yyy')\n\n  let g:plugs.yyy.tag = 'yyy'\n  PlugUpdate\n  Log getline(1, '$')\n\n  PlugDiff\n  \" 1 plugin(s) updated.\n  \" [==]\n  \"\n  \" Last update:\n  \" ------------\n  \"\n  \" - xxx:\n  \"   * 7faa9b2 update-xxx (0 seconds ago)\n  \"\n  \" Pending updates:\n  \" ----------------\n  \"\n  \" N/A\n  \"\n  Log getline(1, '$')\n  AssertEqual 14, line('$')\n  AssertEqual '1 plugin(s) updated.', getline(1)\n  AssertEqual '[==]', getline(2)\n  AssertEqual 'Last update:', getline(4)\n  AssertEqual '- xxx:', getline(7)\n  Assert !empty(mapcheck('o'))\n  Assert !empty(mapcheck('X'))\n  Assert !empty(mapcheck(\"\\<cr>\"))\n  q\n\n**********************************************************************\n~ On-demand loading / Partial installation/update ~\n**********************************************************************\n\nExecute (Trying to execute on-demand commands when plugin is not installed):\n  call ReloadPlug()\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'on': ['EasyAlign', 'LiveEasyAlign!'] }\n  call plug#end()\n\n  Assert exists(':EasyAlign')\n  Assert exists(':LiveEasyAlign')\n  AssertThrows EasyAlign\n  AssertThrows LiveEasyAlign\n  Assert !exists(':EasyAlign')\n  Assert !exists(':LiveEasyAlign')\n\nExecute (New set of plugins):\n  call ReloadPlug()\n  call plug#begin()\n  Plug 'junegunn/vim-fnr'\n  Plug 'junegunn/vim-pseudocl'\n  Plug 'junegunn/vim-easy-align', { 'on': 'EasyAlign' }\n  Plug 'junegunn/vim-redis',      { 'for': 'redis' }\n  let user_autocmd = {}\n  autocmd! User vim-fnr let user_autocmd.fnr = 1\n  autocmd! User vim-easy-align let user_autocmd.easy_align = 1\n  autocmd! User vim-redis let user_autocmd.redis = 1\n  call plug#end()\n\nExecute (Check commands):\n  Assert !exists(':FNR'),          'FNR command should not be found'\n  Assert !exists(':RedisExecute'), 'RedisExecute command should not be found'\n  Assert empty(user_autocmd)\n\nExecute (Partial PlugInstall):\n  PlugInstall vim-fnr vim-easy-align\n  AssertExpect 'vim-fnr', 1\n  q\n\n  PlugInstall vim-fnr vim-easy-align 1\n  AssertExpect 'vim-fnr', 1\n  AssertExpect 'vim-easy-align', 1\n  AssertEqual g:first_rtp, split(&rtp, ',')[0]\n  AssertEqual g:last_rtp, split(&rtp, ',')[-1]\n  q\n\nGiven (Unaligned code):\n  a=1\n  aa=2\n\nExecute (Check installed plugins):\n  call EnsureLoaded()\n  Assert exists(':FNR'),           'FNR command should be found'\n  Assert !exists(':RedisExecute'), 'RedisExecute command still should not be found'\n\n  Assert exists(':EasyAlign'), 'EasyAlign command should be found'\n  %EasyAlign=\n\nExpect (Aligned code):\n  a  = 1\n  aa = 2\n\nThen (autocmd executed):\n  Assert user_autocmd.easy_align\n  AssertEqual 1, len(user_autocmd)\n\nGiven:\nExecute (Partial PlugUpdate):\n  PlugUpdate vim-redis\n  q\n\nExecute (On-demand loading based on filetypes):\n  Assert !exists(':RedisExecute'), 'RedisExecute command still should not be found'\n  set ft=redis\n  Assert exists(':RedisExecute'), 'RedisExecute command is now found'\n  Assert user_autocmd.redis\n  AssertEqual 2, len(user_autocmd)\n\n  autocmd! User\n  unlet user_autocmd\n\n**********************************************************************\n~ Local (unmanaged) plugins\n**********************************************************************\n\nExecute (Add unmanaged plugin):\n  let fzf = expand('$PLUG_FIXTURES/fzf')\n  call RmRf(fzf)\n  Log fzf\n\n  call plug#begin()\n  Plug fzf, { 'on': 'SomeCommand' }\n  call plug#end()\n\n  \" Check uri field\n  Assert !has_key(g:plugs.fzf, 'uri'), 'Should not have uri field'\n\n  \" Check dir field\n  AssertEqual fzf.'/', g:plugs.fzf.dir\n\n  \" Trailing slashes and backslashes should be stripped\n  for suffix in ['///', '/\\/\\/']\n    call plug#begin()\n    Plug fzf.suffix, { 'on': 'SomeCommand' }\n    call plug#end()\n\n    \" Check dir field\n    AssertEqual fzf.'/', g:plugs.fzf.dir\n  endfor\n\nExecute (Plug block for following tests):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align'\n  Plug fzf, { 'on': 'SomeCommand' }\n  call plug#end()\n  \" Remove plugins from previous tests\n  PlugClean!\n  q\n\nExecute (PlugInstall will only install vim-easy-align):\n  PlugInstall\n  Log getline(1, '$')\n  AssertExpect 'fzf', 0\n  q\n\nExecute (PlugUpdate will only update vim-easy-align):\n  PlugUpdate\n  Log getline(1, '$')\n  AssertExpect 'fzf', 0\n  q\n\nExecute (PlugClean should not care about unmanaged plugins):\n  PlugClean\n  Log getline(1, '$')\n  AssertExpect 'fzf', 0\n  q\n\nExecute (PlugStatus should point out that the plugin is missing):\n  PlugStatus\n  Log getline(1, '$')\n  AssertExpect 'x fzf', 1\n  AssertExpect 'Not found', 1\n  q\n\nExecute (Deploy unmanaged plugin):\n  Assert !exists(':FZF'), ':FZF command should not exist'\n  call RmRf(fzf)\n  Log system(printf('cp -r \"/tmp/vim-plug-test/fzf\" \"%s\"', fzf))\n\nExecute (PlugUpdate still should not care):\n  PlugUpdate\n  Log getline(1, '$')\n  AssertExpect 'fzf', 0\n  q\n\nExecute (PlugStatus with no error):\n  PlugStatus\n  Log getline(1, '$')\n  AssertExpect 'x fzf', 0\n  AssertExpect 'Not found', 0\n  q\n\nExecute (Check &rtp after SomeCommand):\n  Log &rtp\n  Assert &rtp !~ 'fzf'\n  silent! SomeCommand\n  Assert &rtp =~ 'fzf'\n  AssertEqual g:first_rtp, split(&rtp, ',')[0]\n  AssertEqual g:last_rtp, split(&rtp, ',')[-1]\n\nExecute (PlugClean should not care about frozen plugins):\n  call plug#begin()\n  Plug 'xxx/vim-easy-align', { 'frozen': 1 }\n  call plug#end()\n  PlugClean\n  AssertExpect 'Already clean', 1\n  q\n\nExecute (Common parent):\n  call plug#begin()\n  Plug 'junegunn/vim-pseudocl'\n  Plug 'junegunn/vim-fnr'\n  Plug 'junegunn/vim-oblique'\n  call plug#end()\n\n  PlugInstall\n  Log getline(1, '$')\n  AssertExpect! '[===]', 1\n  q\n\n  unlet fzf\n\n**********************************************************************\n~ Frozen plugins\n**********************************************************************\n- We've decided to install plugins that are frozen: see #113\nExecute (Frozen plugin are not ~~installed nor~~ updated):\n  \" Remove plugins\n  call plug#begin()\n  call plug#end()\n  PlugClean!\n  q\n\n  \" vim-easy-align is not found, so it will be installed even though it's frozen\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'frozen': 1 }\n  call plug#end()\n  PlugInstall\n  AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ \"vim-easy-align\"'))\n  q\n\n  \" Remove plugins again\n  call plug#begin()\n  call plug#end()\n  PlugClean!\n  q\n\n  \" PlugUpdate will do the same\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'frozen': 1 }\n  call plug#end()\n  PlugInstall\n  AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ \"vim-easy-align\"'))\n  q\n\n  \" Since vim-easy-align already exists, PlugInstall or PlugUpdate will skip it\n  redir => out\n  silent PlugInstall\n  redir END\n  Assert out =~ 'No plugin to install'\n\n  redir => out\n  silent PlugUpdate\n  redir END\n  Assert out =~ 'No plugin to update'\n\nExecute (But you can still install it if the name is given as the argument):\n  PlugInstall vim-easy-align\n  Log getline(1, '$')\n  AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ \"vim-easy-align\"'))\n  q\n\n  PlugUpdate vim-easy-align\n  Log getline(1, '$')\n  AssertEqual 1, len(filter(getline(1, '$'), 'v:val =~ \"vim-easy-align\"'))\n  q\n\n**********************************************************************\n~ Retry\n**********************************************************************\n\nExecute (Retry failed tasks):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align'\n  Plug 'junegunn/aaaaaaaaaaaaaa'\n  call plug#end()\n\n  PlugInstall\n  Log getline(1, '$')\n  AssertExpect 'x aaa', 1\n  AssertExpect '- vim-easy-align', 1\n  normal R\n  Log getline(1, '$')\n  AssertExpect 'x aaa', 1\n  AssertExpect '- vim-easy-align', 0\n  AssertExpect! '[x]', 1\n  q\n\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align'\n  Plug 'junegunn/aaaaaaaaaaaaaa'\n  Plug 'junegunn/bbbbbbbbbbbbbb'\n  Plug 'junegunn/cccccccccccccc'\n  call plug#end()\n\n  \" Ruby installer\n  PlugUpdate\n  normal R\n  AssertExpect '- vim-easy-align', 0\n  AssertExpect! '[xxx]', 1\n  q\n\n  \" Vim installer\n  PlugUpdate 1\n  normal R\n  AssertExpect '- vim-easy-align', 0\n  AssertExpect! '[xxx]', 1\n  q\n\n**********************************************************************\n~ Post-update hook (`do` option)\n**********************************************************************\n\nExecute (Cleanup):\n  call plug#begin()\n  call plug#end()\n  PlugClean!\n  q\n\nExecute (On install):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': 'touch installed' }\n  Plug 'junegunn/vim-pseudocl'\n  Plug 'junegunn/seoul256.vim'\n  Plug 'junegunn/goyo.vim'\n  Plug 'yous/subsubmodule'\n  call plug#end()\n\n  silent PlugInstall\n  q\n\n  Assert filereadable(g:plugs['vim-easy-align'].dir.'/installed'),\n    \\ 'vim-easy-align/installed should exist'\n  Assert !filereadable(g:plugs['vim-pseudocl'].dir.'/installed'),\n    \\ 'vim-pseudocl/installed should not exist'\n  AssertEqual ' ', system('cd '.g:plugs['subsubmodule'].dir.' && git submodule status')[0],\n    \\ 'subsubmodule/subsubmodule should be initialized'\n\nExecute (On update):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': 'touch updated' }\n  Plug 'junegunn/vim-pseudocl', { 'do': 'touch updated' }\n  Plug 'junegunn/seoul256.vim'\n  Plug 'junegunn/goyo.vim'\n  Plug 'yous/subsubmodule'\n  call plug#end()\n\n  \" New commits on remote\n  call system('cd /tmp/vim-plug-test/junegunn/vim-pseudocl && git commit --allow-empty -m \"update\"')\n\n  silent PlugUpdate\n  Log getline(1, '$')\n  q\n\n  Assert !filereadable(g:plugs['vim-easy-align'].dir.'/updated'),\n    \\ 'vim-easy-align/updated should not exist'\n  Assert filereadable(g:plugs['vim-pseudocl'].dir.'/updated'),\n    \\ 'vim-pseudocl/updated should exist'\n\nExecute (When already installed):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': 'touch installed2' }\n  Plug 'junegunn/vim-pseudocl', { 'commit': '7f8cd78' }\n  Plug 'junegunn/seoul256.vim', { 'branch': 'no-t_co' }\n  Plug 'junegunn/goyo.vim', { 'tag': '1.5.3' }\n  Plug 'yous/subsubmodule'\n  call plug#end()\n\n  PlugInstall\n  q\n  Assert !filereadable(g:plugs['vim-easy-align'].dir.'/installed2'),\n    \\ 'vim-easy-align/installed2 should not exist'\n  AssertNotEqual '7f8cd78cb1fe52185b98b16a3749811f0cc508af', GitCommit('vim-pseudocl')\n  AssertNotEqual 'no-t_co', GitBranch('seoul256.vim')\n  AssertNotEqual '1.5.3', GitTag('goyo.vim')\n\nExecute (PlugInstall!):\n  silent PlugInstall!\n  q\n  Assert filereadable(g:plugs['vim-easy-align'].dir.'/installed2'),\n    \\ 'vim-easy-align/installed2 should exist'\n  AssertEqual '7f8cd78cb1fe52185b98b16a3749811f0cc508af', GitCommit('vim-pseudocl')\n  \" Was updated to the default branch of origin by previous PlugUpdate\n  AssertEqual 'master', GitBranch('seoul256.vim')\n  AssertEqual '1.5.3', GitTag('goyo.vim')\n\nExecute (When submodules are not initialized):\n  call system(printf('cd %s && git submodule deinit subsubmodule', g:plugs['subsubmodule'].dir))\n\n  silent PlugInstall!\n  q\n\n  AssertEqual ' ', system(printf('cd %s && git submodule status', g:plugs['subsubmodule'].dir))[0],\n    \\ 'subsubmodule/subsubmodule should be initialized'\n\nExecute (When already updated):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': 'touch updated2' }\n  Plug 'junegunn/vim-pseudocl', { 'commit': 'dd507ca' }\n  Plug 'junegunn/seoul256.vim', { 'branch': 'master' }\n  Plug 'junegunn/goyo.vim', { 'tag': '1.6.0' }\n  Plug 'yous/subsubmodule'\n  call plug#end()\n\n  PlugUpdate\n  q\n  Assert !filereadable(g:plugs['vim-easy-align'].dir.'/updated2'),\n    \\ 'vim-easy-align/updated2 should not exist'\n  AssertEqual 'dd507ca0d5f3fdf0d522558cc5ecffdabf824469', GitCommit('vim-pseudocl')\n  AssertEqual 'master', GitBranch('seoul256.vim')\n  AssertEqual '1.6.0', GitTag('goyo.vim')\n\nExecute (PlugUpdate!):\n  silent PlugUpdate!\n  q\n  Assert filereadable(g:plugs['vim-easy-align'].dir.'/updated2'),\n    \\ 'vim-easy-align/updated2 should exist'\n\nExecute (When submodules are not initialized):\n  call system(printf('cd %s && git submodule deinit subsubmodule', g:plugs['subsubmodule'].dir))\n\n^ #481 submodule update should use standard shell\n  let sh = &shell\n  set sh=/bin/echo\n  silent PlugUpdate!\n  let &shell = sh\n  unlet sh\n  q\n  AssertEqual ' ', system(printf('cd %s && git submodule status', g:plugs['subsubmodule'].dir))[0],\n    \\ 'subsubmodule/subsubmodule should be initialized'\n\nExecute (Using Funcref):\n  function! PlugUpdated(info)\n    call system('touch '. a:info.name . a:info.status . a:info.force . len(a:info))\n  endfunction\n\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': function('PlugUpdated') }\n  Plug 'junegunn/vim-pseudocl',   { 'do': function('PlugUpdated') }\n  call plug#end()\n\n  call system('cd /tmp/vim-plug-test/junegunn/vim-easy-align && git commit --allow-empty -m \"update\"')\n  call system('cd '.g:plugs['vim-easy-align'].dir.' && git reset --hard HEAD^')\n  call RmRf(g:plugs['vim-pseudocl'].dir)\n\n  PlugUpdate\n  Log getline(1, '$')\n  q\n  Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignupdated03'),\n    \\ 'vim-easy-align/vim-easy-alignupdated03 should exist'\n  Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclinstalled03'),\n    \\ 'vim-pseudocl/vim-pseudoclinstalled03 should exist'\n\n  call RmRf(g:plugs['vim-pseudocl'].dir)\n  PlugInstall!\n  q\n  Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignunchanged13'),\n    \\ 'vim-easy-align/vim-easy-alignunchanged13 should exist'\n  Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclinstalled13'),\n    \\ 'vim-pseudocl/vim-pseudoclinstalled13 should exist'\n\n  call system('cd '.g:plugs['vim-easy-align'].dir.' && git reset --hard HEAD^')\n  PlugUpdate!\n  q\n  Assert filereadable(g:plugs['vim-easy-align'].dir.'/vim-easy-alignupdated13'),\n    \\ 'vim-easy-align/vim-easy-alignupdated13 should exist'\n  Assert filereadable(g:plugs['vim-pseudocl'].dir.'/vim-pseudoclunchanged13'),\n    \\ 'vim-pseudocl/vim-pseudoclunchanged13 should exist'\n\nExecute (Post-update hook output; success and failure):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': 'xxx-non-existent-command-xxx' }\n  Plug 'junegunn/vim-pseudocl',   { 'do': 'true' }\n  call plug#end()\n\n  silent PlugInstall! 1\n  AssertEqual '- Post-update hook for vim-pseudocl ... OK', getline(5)\n  AssertEqual 'x Post-update hook for vim-easy-align ... Exit status: 127', getline(6)\n  q\n\nExecute (Post-update hook output; invalid type or funcref):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': ':echo 1' }\n  Plug 'junegunn/vim-pseudocl',   { 'do': function('call') }\n  call plug#end()\n  let g:plugs['vim-easy-align'].do = 1\n\n  silent PlugInstall! 1\n  AssertEqual 'x Post-update hook for vim-pseudocl ... Vim(call):E119: Not enough arguments for function: call', getline(5)\n  AssertEqual 'x Post-update hook for vim-easy-align ... Invalid hook type', getline(6)\n  q\n\nExecute (Should not run when failed to update):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'do': 'touch failed'     }\n  Plug 'junegunn/vim-pseudocl',   { 'do': 'touch not-failed' }\n  call plug#end()\n\n  \" Invalid remote URL\n  call system(printf('cd %s && git remote set-url origin xxx', g:plugs['vim-easy-align'].dir))\n\n  \" New commits on remote\n  call system('cd /tmp/vim-plug-test/junegunn/vim-easy-align && git commit --allow-empty -m \"update\"')\n  call system('cd /tmp/vim-plug-test/junegunn/vim-pseudocl && git commit --allow-empty -m \"update\"')\n\n  silent PlugUpdate\n  Log getline(1, '$')\n  q\n\n  Assert !filereadable(g:plugs['vim-easy-align'].dir.'/failed'),\n    \\ 'vim-easy-align/failed should not exist'\n  Assert filereadable(g:plugs['vim-pseudocl'].dir.'/not-failed'),\n    \\ 'vim-pseudocl/not-failed should exist'\n\nExecute (Vim command with : prefix):\n  call plug#begin()\n  Plug 'junegunn/vim-pseudocl', { 'do': ':call setline(2, 12345)' }\n  call plug#end()\n\n  PlugInstall!\n  Log getline(1, '$')\n  AssertEqual '12345', getline(2)\n  q\n\nExecute (Vim command with : prefix closing the window):\n  call plug#begin()\n  Plug 'junegunn/vim-pseudocl', { 'do': ':close' }\n  call plug#end()\n\n  redir => out\n  PlugInstall!\n  redir END\n  Assert out =~ 'vim-plug was terminated'\n  Assert out =~ 'of vim-pseudocl'\n\nExecute (Invalid vim command in post-update hook):\n  call plug#begin()\n  Plug 'junegunn/vim-pseudocl', { 'do': ':nosuchcommand' }\n  call plug#end()\n\n  PlugInstall!\n  Log getline(1, '$')\n  AssertExpect! 'x Post-update hook for vim-pseudocl ... Vim:E492: Not an editor command: nosuchcommand', 1\n  q\n\n**********************************************************************\n~ Overriding `dir`\n**********************************************************************\n\nExecute (Using custom dir):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align'\n  call plug#end()\n  Assert isdirectory(g:plugs['vim-easy-align'].dir)\n\n  call RmRf('/tmp/vim-plug-test/easy-align')\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align', { 'dir': '/tmp/vim-plug-test/easy-align' }\n  call plug#end()\n  AssertEqual '/tmp/vim-plug-test/easy-align/', g:plugs['vim-easy-align'].dir\n\n  PlugClean!\n  Assert !isdirectory(g:plugs['vim-easy-align'].dir)\n  q\n\n  PlugInstall\n  q\n  Assert isdirectory(g:plugs['vim-easy-align'].dir)\n\n**********************************************************************\n~ On-demand loading load order\n**********************************************************************\nBefore (Clear global vars):\n  let g:xxx = []\n  set rtp-=$PLUG_FIXTURES/xxx/\n  set rtp-=$PLUG_FIXTURES/xxx/after\n\nExecute (Immediate loading):\n  call ReloadPlug()\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx'\n  call plug#end()\n\n  \" FIXME:\n  \" Different result when Vader is run from commandline with `-c` option\n  Log g:xxx\n  if has('vim_starting')\n    AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx\n  else\n    AssertEqual ['xxx/plugin', 'xxx/after/plugin', 'xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx\n  endif\n\nExecute (Command-based on-demand loading):\n  call ReloadPlug()\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx', { 'on': 'XXX' }\n  call plug#end()\n\n  AssertEqual [], g:xxx\n\n  silent! XXX\n  AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin'], g:xxx\n\n  setf xxx\n  AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/ftplugin', 'xxx/after/ftplugin', 'xxx/indent', 'xxx/after/indent', 'xxx/syntax', 'xxx/after/syntax'], g:xxx\n\nExecute (Filetype-based on-demand loading):\n  call ReloadPlug()\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx', { 'for': 'xxx' }\n  Plug '$PLUG_FIXTURES/yyy', { 'for': 'yyy' }\n  call plug#end()\n\n  AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx\n\n  setf xxx\n  AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/syntax', 'xxx/after/syntax', 'xxx/ftplugin', 'xxx/after/ftplugin', 'xxx/indent', 'xxx/after/indent'], g:xxx\n\n  \" syntax/xxx.vim and after/syntax/xxx.vim should not be loaded (#410)\n  setf yyy\n  AssertEqual ['yyy/ftdetect', 'yyy/after/ftdetect', 'yyy/plugin', 'yyy/after/plugin'], g:yyy\n\nBefore:\n\n**********************************************************************\n~ plug#helptags()\n**********************************************************************\n\nExecute (plug#helptags):\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx'\n  Plug '$PLUG_FIXTURES/yyy', { 'rtp': 'rtp' }\n  call plug#end()\n  silent! call delete(expand('$PLUG_FIXTURES/xxx/doc/tags'))\n  silent! call delete(expand('$PLUG_FIXTURES/yyy/rtp/doc/tags'))\n  Assert !filereadable(expand('$PLUG_FIXTURES/xxx/doc/tags'))\n  Assert !filereadable(expand('$PLUG_FIXTURES/yyy/rtp/doc/tags'))\n  AssertEqual 1, plug#helptags()\n  Assert filereadable(expand('$PLUG_FIXTURES/xxx/doc/tags'))\n  Assert filereadable(expand('$PLUG_FIXTURES/yyy/rtp/doc/tags'))\n\n**********************************************************************\n~ Manual loading\n**********************************************************************\n\nExecute (plug#load - invalid arguments):\n  call ResetPlug()\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx', { 'for': 'xxx' }\n  Plug '$PLUG_FIXTURES/yyy', { 'for': 'yyy' }\n  call plug#end()\n  AssertEqual 0, plug#load()\n  AssertEqual 0, plug#load('non-existent-plugin')\n  AssertEqual 0, plug#load('non-existent-plugin', 'another-non-existent-plugin')\n  AssertEqual 1, plug#load('xxx')\n  AssertEqual 0, plug#load('xxx', 'non-existent-plugin')\n  AssertEqual 0, plug#load('non-existent-plugin', 'xxx')\n\nExecute (plug#load - list argument (#638)):\n  redir => out\n  call plug#load(keys(g:plugs))\n  redir END\n  AssertEqual '', out\n\nExecute (on: []):\n  call plug#begin()\n  Plug 'junegunn/rust.vim', { 'on': [] }\n  call plug#end()\n  PlugInstall\n  q\n\nExecute (PlugStatus reports (not loaded)):\n  PlugStatus\n  AssertExpect 'not loaded', 1\n  q\n\nExecute (plug#load to load it):\n  tabnew test.rs\n  \" Vader will switch tab to [Vader-workbench] after Log\n  \" Log &filetype\n  AssertEqual 1, plug#load('rust.vim')\n  AssertEqual 'rust', &filetype\n  q\n\nExecute (PlugStatus should not contain (not loaded)):\n  PlugStatus\n  AssertExpect 'not loaded', 0\n  q\n\nExecute (Load plugin from PlugStatus screen with L key in normal mode):\n  call ResetPlug()\n  unlet! g:yyy\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/yyy', { 'on': [] }\n  call plug#end()\n\n  PlugStatus\n  AssertExpect 'not loaded', 1\n  Assert !exists('g:yyy'), 'yyy not loaded'\n  /not loaded\n  normal L\n  AssertExpect 'not loaded', 0\n  Assert exists('g:yyy'), 'yyy loaded'\n  q\n\nExecute (Load plugin from PlugStatus screen with L key in visual mode):\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/z1', { 'on':  [] }\n  Plug '$PLUG_FIXTURES/z2', { 'for': [] }\n  call plug#end()\n\n  PlugStatus\n  AssertExpect 'not loaded', 2\n  Assert !exists('g:z1'), 'z1 not loaded'\n  Assert !exists('g:z2'), 'z2 not loaded'\n  normal ggVGL\n  AssertExpect 'not loaded', 0\n  Assert exists('g:z1'), 'z1 loaded'\n  Assert exists('g:z2'), 'z2 loaded'\n  q\n\n**********************************************************************\n~ g:plug_window\n**********************************************************************\nExecute (Open plug window in a new tab):\n  \" Without g:plug_window, plug window is open on the left split\n  let tabnr = tabpagenr()\n  PlugStatus\n  AssertEqual tabnr, tabpagenr()\n  AssertEqual 1, winnr()\n\n  \" PlugStatus again inside the window should not change the view\n  normal S\n  AssertEqual tabnr, tabpagenr()\n  AssertEqual 1, winnr()\n  q\n\n  \" Define g:plug_window so that plug window is open in a new tab\n  let g:plug_window = 'tabnew'\n  PlugStatus\n  AssertNotEqual tabnr, tabpagenr()\n\n  \" PlugStatus again inside the window should not change the view\n  let tabnr = tabpagenr()\n  normal S\n  AssertEqual tabnr, tabpagenr()\n  q\n  unlet g:plug_window tabnr\n\n**********************************************************************\n~ g:plug_url_format\n**********************************************************************\nExecute (Using g:plug_url_format):\n  let prev_plug_url_format = g:plug_url_format\n  call plug#begin()\n  let g:plug_url_format = 'git@bitbucket.org:%s.git'\n  Plug 'junegunn/seoul256.vim'\n  let g:plug_url_format = 'git@bitsocket.org:%s.git'\n  Plug 'vim-scripts/beauty256'\n  AssertEqual 'git@bitbucket.org:junegunn/seoul256.vim.git', g:plugs['seoul256.vim'].uri\n  AssertEqual 'git@bitsocket.org:vim-scripts/beauty256.git', g:plugs['beauty256'].uri\n  let g:plug_url_format = prev_plug_url_format\n\n**********************************************************************\n~ U\n**********************************************************************\nExecute (Plug block):\n  call plug#begin()\n  Plug 'junegunn/vim-easy-align'\n  Plug 'junegunn/vim-emoji'\n  call plug#end()\n\nExecute (Update plugin with U key in normal mode):\n  PlugStatus\n  /emoji\n  normal U\n  Log getline(1, '$')\n  AssertExpect 'Updated', 1\n  AssertExpect 'vim-emoji', 1\n  AssertExpect 'vim-easy-align', 0\n  AssertExpect! '[=]', 1\n\n  \" From PlugInstall screen\n  PlugInstall\n  /easy-align\n  normal U\n  AssertExpect 'Updated', 1\n  AssertExpect 'vim-emoji', 0\n  AssertExpect 'vim-easy-align', 1\n  AssertExpect! '[=]', 1\n  q\n\nExecute (Update plugins with U key in visual mode):\n  silent! call RmRf(g:plugs['vim-easy-align'].dir)\n\n  PlugStatus\n  normal VGU\n  Log getline(1, '$')\n  AssertExpect 'Updated', 1\n  AssertExpect 'vim-emoji', 1\n  AssertExpect 'vim-easy-align', 1\n  AssertExpect! '[==]', 1\n\n  \" From PlugUpdate screen\n  normal VGU\n  Log getline(1, '$')\n  AssertExpect 'Updated', 1\n  AssertExpect 'vim-emoji', 1\n  AssertExpect 'vim-easy-align', 1\n  AssertExpect! '[==]', 1\n  q\n\n**********************************************************************\nExecute (plug#begin should expand env vars):\n  AssertNotEqual '$HOME/.emacs/plugged', expand('$HOME/.emacs/plugged')\n  call plug#begin('$HOME/.emacs/plugged')\n  AssertEqual expand('$HOME/.emacs/plugged'), g:plug_home\n\n**********************************************************************\nExecute (Plug directory with comma):\n  call plug#begin(g:temp_plugged . '/p,l,u,g,g,e,d')\n  Plug 'junegunn/vim-emoji'\n  call plug#end()\n  Log &rtp\n\n  PlugInstall\n  q\n  let found = filter(split(globpath(&rtp, 'README.md'), '\\n'), 'v:val =~ \",\"')\n  Log found\n  AssertEqual 1, len(found)\n  unlet found\n\n**********************************************************************\nExecute (Strict load order):\n  let g:total_order = []\n  call ReloadPlug()\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx'\n  Plug '$PLUG_FIXTURES/yyy', { 'for': ['xxx'] }\n  call plug#end()\n  call EnsureLoaded()\n  setf xxx\n  Log 'Case 1: ' . &rtp\n  AssertEqual ['yyy/ftdetect', 'yyy/after/ftdetect', 'xxx/ftdetect', 'xxx/after/ftdetect'], g:total_order[0:3]\n  Assert index(g:total_order, 'xxx/plugin') < index(g:total_order, 'yyy/plugin')\n  Assert index(g:total_order, 'xxx/after/plugin') < index(g:total_order, 'yyy/after/plugin')\n  let len = len(split(&rtp, ','))\n\n  let g:total_order = []\n  call ReloadPlug()\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx', { 'for': ['xxx'] }\n  Plug '$PLUG_FIXTURES/yyy'\n  call plug#end()\n  call EnsureLoaded()\n  set rtp^=manually-prepended\n  set rtp+=manually-appended\n  setf xxx\n  Log 'Case 2: ' . &rtp\n  AssertEqual 'manually-prepended', split(&rtp, ',')[3]\n  AssertEqual 'manually-appended',  split(&rtp, ',')[-4]\n  AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'yyy/ftdetect', 'yyy/after/ftdetect'], g:total_order[0:3]\n  Assert index(g:total_order, 'yyy/plugin') < index(g:total_order, 'xxx/plugin')\n  Assert index(g:total_order, 'yyy/after/plugin') < index(g:total_order, 'xxx/after/plugin')\n  AssertEqual len + 2, len(split(&rtp, ','))\n\n  let g:total_order = []\n  call ReloadPlug()\n  set rtp^=manually-prepended\n  set rtp+=manually-appended\n  call plug#begin()\n  Plug '$PLUG_FIXTURES/xxx', { 'for': ['xxx'] }\n  Plug '$PLUG_FIXTURES/yyy', { 'for': ['xxx'] }\n  call plug#end()\n  call EnsureLoaded()\n  setf xxx\n  Log 'Case 3: ' . &rtp\n  AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'yyy/ftdetect', 'yyy/after/ftdetect'], g:total_order[0:3]\n  Assert index(g:total_order, 'xxx/plugin') < index(g:total_order, 'yyy/plugin')\n  Assert index(g:total_order, 'xxx/after/plugin') < index(g:total_order, 'yyy/after/plugin')\n  AssertEqual len + 2, len(split(&rtp, ','))\n\n**********************************************************************\nExecute (PlugClean should not try to remove unmanaged plugins inside g:plug_home):\n  call plug#begin('$PLUG_FIXTURES')\n  Plug '$PLUG_FIXTURES/ftplugin-msg', { 'for': [] }\n  Plug '$PLUG_FIXTURES/fzf'\n  Plug '$PLUG_FIXTURES/xxx'\n  Plug '$PLUG_FIXTURES/yyy'\n  Plug '$PLUG_FIXTURES/cant-delete'\n  call plug#end()\n\n  \" Remove z1, z2\n  PlugClean!\n  AssertExpect '^\\~ ', 2\n  AssertExpect 'Already clean', 0\n\n  PlugClean!\n  AssertExpect '^\\~ ', 0\n  AssertExpect 'Already clean', 1\n  q\n\n**********************************************************************\nExecute (PlugSnapshot / #154 issues with paths containing spaces):\n  let $TMPDIR = '/tmp'\n  call plug#begin('$TMPDIR/plug with spaces')\n  Plug 'junegunn/vim-easy-align'\n  Plug 'junegunn/seoul256.vim'\n  call plug#end()\n\n  PlugClean!\n  PlugInstall\n  call plug#load('vim-easy-align') \" Should properly handle paths with spaces\n  PlugSnapshot\n  AssertEqual '\" Generated by vim-plug', getline(1)\n  AssertEqual 0, stridx(getline(6), \"silent! let g:plugs['seoul256.vim'].commit = '\")\n  AssertEqual 0, stridx(getline(7), \"silent! let g:plugs['vim-easy-align'].commit = '\")\n  AssertEqual 'vim', &filetype\n\n  call delete(g:plug_home.'/snapshot.vim')\n  execute 'PlugSnapshot' escape(g:plug_home.'/snapshot.vim', ' ')\n  AssertEqual 'vim', &filetype\n  AssertEqual 'snapshot.vim', fnamemodify(expand('%'), ':t')\n  q\n\nExecute(PlugSnapshot! to overwrite existing file):\n  call writefile(['foobar'], g:plug_home.'/snapshot.vim')\n  AssertEqual 'foobar', readfile(g:plug_home.'/snapshot.vim')[0]\n  execute 'PlugSnapshot!' escape(g:plug_home.'/snapshot.vim', ' ')\n  AssertEqual '\" Generated by vim-plug', readfile(g:plug_home.'/snapshot.vim')[0]\n  q\n\n**********************************************************************\nExecute (#221 Shallow-clone and tag option):\n  call plug#begin(g:temp_plugged)\n  Plug 'junegunn/goyo.vim'\n  call plug#end()\n  PlugInstall\n\n  execute 'cd' g:plugs['goyo.vim'].dir\n  Assert len(split(system('git log --oneline'), '\\n')) == 1\n  Assert filereadable('.git/shallow')\n\n  Plug 'junegunn/goyo.vim', { 'tag': '1.5.3' }\n  PlugUpdate\n  q\n\n  Assert len(split(system('git log --oneline'), '\\n')) > 1\n  Assert system('git describe --tag') =~ '^1.5.3'\n  Assert !filereadable('.git/shallow')\n  cd -\n\nExecute (#221 Shallow-clone disabled by g:plug_shallow = 0):\n  call plug#begin(g:temp_plugged)\n  call plug#end()\n  PlugClean!\n\n  let g:plug_shallow = 0\n  call plug#begin(g:temp_plugged)\n  Plug 'junegunn/goyo.vim'\n  call plug#end()\n  PlugInstall\n  q\n\n  execute 'cd' g:plugs['goyo.vim'].dir\n  Assert len(split(system('git log --oneline'), '\\n')) > 1, 'not shallow'\n  Assert !filereadable('.git/shallow'), 'not shallow'\n  cd -\n  unlet g:plug_shallow\n\nExecute (#221 Shallow-clone disabled by tag):\n  call plug#begin(g:temp_plugged)\n  call plug#end()\n  PlugClean!\n\n  call plug#begin(g:temp_plugged)\n  Plug 'junegunn/goyo.vim', { 'tag': '1.5.3' }\n  call plug#end()\n  Assert !isdirectory(g:plugs['goyo.vim'].dir)\n  PlugInstall\n  Assert isdirectory(g:plugs['goyo.vim'].dir)\n  q\n\n  execute 'cd' g:plugs['goyo.vim'].dir\n  Assert system('git describe --tag') =~ '^1.5.3'\n  Assert len(split(system('git log --oneline'), '\\n')) > 1\n  Assert !filereadable('.git/shallow')\n  cd -\n\nExecute (Commit hash support):\n  \" Get goyo back to master\n  call plug#begin(g:temp_plugged)\n  Plug 'junegunn/goyo.vim'\n  call plug#end()\n  PlugUpdate\n\n  call plug#begin(g:temp_plugged)\n  Plug 'junegunn/goyo.vim',  { 'commit': 'ffffffff' }\n  Plug 'junegunn/vim-emoji', { 'commit': '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a' }\n  call plug#end()\n  PlugUpdate\n  Log getline(1, '$')\n  AssertEqual 'x goyo.vim:', getline(5)\n  AssertEqual '    fatal: invalid reference: ffffffff', getline(6)\n  AssertEqual 0, stridx(getline(7), '- vim-emoji: HEAD is now at 9db7fcf')\n\n  let hash = system(printf('cd %s && git rev-parse HEAD', g:plugs['vim-emoji'].dir))[:-2]\n  AssertEqual '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a', hash\n\n  \" Validate error formatting\n  PlugStatus\n  Log getline(1, '$')\n  AssertEqual ['Finished. 1 error(s).',\n              \\'[==]',\n              \\'',\n              \\'x goyo.vim:'], getline(1, 4)\n  Assert getline(5) =~ '    Invalid HEAD (expected: fffffff, actual: [0-9a-f]\\{7})'\n  AssertEqual ['    PlugUpdate required.',\n              \\'- vim-emoji: OK'], getline(6, '$')\n\n  \" PlugDiff should show pending updates for vim-emoji\n  PlugDiff\n  Log getline(1, '$')\n  AssertEqual '0 plugin(s) updated. 1 plugin(s) have pending updates.', getline(1)\n  Assert !empty(mapcheck('o'))\n  Assert empty(mapcheck('X'))\n  Assert !empty(mapcheck(\"\\<cr>\"))\n\n  \" The exact hash values in PlugSnapshot output\n  PlugSnapshot\n  Log getline(1, '$')\n  AssertEqual \"silent! let g:plugs['goyo.vim'].commit = 'ffffffff'\", getline(6)\n  AssertEqual \"silent! let g:plugs['vim-emoji'].commit = '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a'\", getline(7)\n  AssertEqual 10, line('$')\n  q\n\nExecute (Commit hash support - cleared):\n  call plug#begin(g:temp_plugged)\n  Plug 'junegunn/goyo.vim'\n  Plug 'junegunn/vim-emoji'\n  call plug#end()\n\n  PlugInstall\n  let hash = system(printf('cd %s && git rev-parse HEAD', g:plugs['vim-emoji'].dir))[:-2]\n  AssertEqual '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a', hash\n\n  PlugUpdate\n  let hash = system(printf('cd %s && git rev-parse HEAD', g:plugs['vim-emoji'].dir))[:-2]\n  AssertNotEqual '9db7fcfee0d90dafdbcb7a32090c0a9085eb054a', hash\n  q\n\nExecute (#371 - 'as' option):\n  call plug#begin()\n  Plug 'jg/goyo.vim'\n  Plug 'junegunn/goyo.vim', {'as': 'yogo'}\n  call plug#end()\n  AssertEqual ['goyo.vim', 'yogo'], sort(keys(g:plugs))\n  Log g:plugs\n  Assert g:plugs.yogo.dir =~# '/yogo/$'\n\n  call plug#begin()\n  Plug 'junegunn/goyo.vim', {'as': 'yogo', 'dir': '/tmp/vim-plug-test/gogo'}\n  call plug#end()\n  AssertEqual ['yogo'], sort(keys(g:plugs))\n  AssertEqual '/tmp/vim-plug-test/gogo/', g:plugs.yogo.dir\n\nExecute (#427 - Tag option with wildcard (requires git 1.9.2 or above)):\n  if str2nr(split(split(system('git --version'))[-1], '\\.')[0]) < 2\n    Log 'tag with wildcard requires git 1.9.2 or above'\n  else\n    call plug#begin()\n    Plug 'junegunn/vim-easy-align', { 'tag': '2.9.*' }\n    call plug#end()\n    PlugInstall!\n    Log getline(1, '$')\n    AssertExpect! '- Latest tag for 2.9.* -> 2.9.7 (vim-easy-align)', 1\n    q\n    AssertEqual '2.9.7', GitTag('vim-easy-align')\n  endif\n\nExecute (#530 - Comparison of compatible git URIs):\n  \" .git suffix\n  Assert CompareURI('https://github.com/junegunn/vim-plug.git', 'https://github.com/junegunn/vim-plug')\n\n  \" user@\n  Assert CompareURI('https://github.com/junegunn/vim-plug.git', 'https://user@github.com/junegunn/vim-plug.git')\n\n  \" git::@\n  Assert CompareURI('https://github.com/junegunn/vim-plug.git', 'https://git::@github.com/junegunn/vim-plug.git')\n\n  \" https and ssh\n  Assert CompareURI('https://github.com/junegunn/vim-plug.git', 'git@github.com:junegunn/vim-plug.git')\n\n  \" file://\n  Assert CompareURI('file:///tmp/vim-plug', '/tmp/vim-plug')\n  Assert CompareURI('file:///tmp/vim-plug', '/tmp/vim-plug/')\n\nExecute (#530 - Comparison of incompatible git URIs):\n  \" Different hostname\n  Assert !CompareURI('https://github.com/junegunn/vim-plug.git', 'https://bitbucket.com/junegunn/vim-plug.git')\n\n  \" Different repository\n  Assert !CompareURI('https://github.com/junegunn/vim-plug.git', 'https://github.com/junegunn/emacs-plug.git')\n\n  \" Different port\n  Assert !CompareURI('https://github.com/junegunn/vim-plug.git', 'https://github.com:12345/junegunn/vim-plug.git')\n\nExecute (#532 - Reuse plug window):\n  let g:plug_window = 'vertical topleft new'\n  let g:plug_pwindow = 'above 12new'\n  call plug#begin()\n  Plug 'junegunn/goyo.vim'\n  call plug#end()\n  PlugInstall\n  call system(printf('cd \"%s\" && git commit --allow-empty -m \"dummy\"', g:plugs['goyo.vim'].dir))\n\n  PlugDiff\n  AssertEqual 1, winnr(), 'Current window is #1 after PlugDiff (but is '.winnr().')'\n  AssertEqual 2, winnr('$'), 'Two windows after PlugDiff (but got '.winnr('$').')'\n\n  \" Open preview window\n  execute \"normal ]]jo\"\n  AssertEqual 2, winnr(), 'Current window is #2 after opening preview (but is '.winnr().')'\n  AssertEqual 3, winnr('$'), 'Three windows with preview (but got '.winnr('$').')'\n\n  \" Move plug window to the right\n  wincmd L\n  AssertEqual 3, winnr(), 'Current window is #3 after moving window (but is '.winnr().')'\n  AssertEqual 3, winnr('$'), 'Three windows after moving window (but got '.winnr('$').')'\n\n  \" Reuse plug window. Preview window is closed.\n  PlugStatus\n  AssertEqual 2, winnr(), 'Current window is #2 after PlugStatus (but is '.winnr().')'\n  AssertEqual 2, winnr('$'), 'Three windows after PlugStatus (but got '.winnr('$').')'\n  q\n\n  unlet g:plug_window g:plug_pwindow\n\nExecute (#766 - Allow cloning into an empty directory):\n  let d = '/tmp/vim-plug-test/goyo-already'\n  call system('rm -rf ' . d)\n  call mkdir(d)\n  call plug#begin()\n  Plug 'junegunn/goyo.vim', { 'dir': d }\n  call plug#end()\n  PlugInstall\n  AssertExpect! '[=]', 1\n  q\n  unlet d\n\nExecute (#982 - PlugClean should report when directories cannot be removed):\n  call plug#begin('$PLUG_FIXTURES')\n  Plug '$PLUG_FIXTURES/ftplugin-msg', { 'for': [] }\n  Plug '$PLUG_FIXTURES/fzf'\n  Plug '$PLUG_FIXTURES/xxx'\n  Plug '$PLUG_FIXTURES/yyy'\n  call plug#end()\n\n  \" Fail to remove cant-delete\n  PlugClean!\n  AssertEqual 'Removed 0 directories. Failed to remove 1 directories.', getline(4)\n  AssertExpect '^x ', 1\n  q\n\n  \" Delete tmp but fail to remove cant-delete\n  call mkdir(expand('$PLUG_FIXTURES/tmp'))\n  PlugClean!\n  AssertEqual 'Removed 1 directories. Failed to remove 1 directories.', getline(4)\n  AssertExpect '^x ', 1\n  AssertExpect '^\\~ ', 1\n  q\n"
  }
]